1515 */
1616package org .culturegraph .mf .morph .functions ;
1717
18- import java .text .ParseException ;
1918import java .text .SimpleDateFormat ;
19+ import java .util .Calendar ;
2020import java .util .Collections ;
21- import java .util .Date ;
21+ import java .util .GregorianCalendar ;
2222import java .util .HashSet ;
2323import java .util .Locale ;
2424import java .util .Set ;
2727
2828/**
2929 * Format date/time strings in Metamorph. By default the input format is
30- * dd.MM.yyyy and the output format is dd. MMMM yyyy.
31- *
30+ * dd.MM.yyyy and the output format is {@link java.text.DateFormat.Field#LONG}.
31+ * <br/>
32+ * The Attribute removeLeadingZeros will remove all leading zeros from all
33+ * numbers in the output date.
34+ * <br/>
35+ * The attribute era is used to specify if the date is BC or AD. Default
36+ * value is AUTO. To understand that, three short examples:
37+ * <ul><li>Input: 20.07.356 (era=BC)</li>
38+ * <li>Output (German location): 20. Juli 0356 v. Chr.</li>
39+ * <ul><li>Input: 20.07.356 (era=AD,removeLeadingZeros=true)</li>
40+ * <li>Output (German location): 20. Juli 356</li>
41+ * <li>Input: 20.07.-356 (era=AUTO)</li>
42+ * <li>Output (German location): 20. Juli 0357 v. Chr. (there is NO year 0;
43+ * see ISO 8601, Proleptic Gregorian Calendar)</li></ul>
44+ * <p/>
3245 * Examples of using this function in Metamorph:
33- * <ul>
34- * <li>Default date format: <code><dateformat /></code></li>
35- * <li>Read ISO-dates and generate German style dates:
36- * <code><dateformat inputformat="yyyy-MM-dd" outputformat="dd.MM.yyyy" /></code></li>
46+ * <ul><li>Default date format: <code><dateformat /></code></li>
47+ * <li>Read ISO-dates and generate German style dates:
48+ * <code><dateformat inputformat="yyyy-MM-dd" outputformat="dd.MM.yyyy" /></code></li>
3749 * </ul>
3850 *
3951 * @author Michael Büchner
@@ -42,11 +54,15 @@ public class DateFormat extends AbstractSimpleStatelessFunction {
4254
4355 public static final String DEFAULT_INPUT_FORMAT = "dd.MM.yyyy" ;
4456 public static final DateFormats DEFAULT_OUTPUT_FORMAT = DateFormats .LONG ;
57+ public static final boolean DEFAULT_REMOVE_LEADING_ZEROS = false ;
58+ public static final Era DEFAULT_ERA = Era .AUTO ;
4559
4660 private static final Set <String > SUPPORTED_LANGUAGES ;
4761
4862 private String inputFormat = DEFAULT_INPUT_FORMAT ;
4963 private DateFormats outputFormat = DEFAULT_OUTPUT_FORMAT ;
64+ private Era era = DEFAULT_ERA ;
65+ private boolean removeLeadingZeros = DEFAULT_REMOVE_LEADING_ZEROS ;
5066 private Locale outputLocale = Locale .getDefault ();
5167
5268 /**
@@ -73,6 +89,29 @@ int getFormatId() {
7389
7490 }
7591
92+ /**
93+ * Supported eras (basically AUTO, AD and BC). Maps to
94+ * {@link java.util.GregorianCalendar}.
95+ *
96+ * @author Michael Büchner
97+ */
98+ public enum Era {
99+ AD (GregorianCalendar .AD ),
100+ BC (GregorianCalendar .BC ),
101+ AUTO (-1 );
102+
103+ private final int eraId ;
104+
105+ Era (final int eraId ) {
106+ this .eraId = eraId ;
107+ }
108+
109+ int getEraId () {
110+ return eraId ;
111+ }
112+
113+ }
114+
76115 static {
77116 final Set <String > set = new HashSet <String >();
78117 Collections .addAll (set , Locale .getISOLanguages ());
@@ -81,15 +120,34 @@ int getFormatId() {
81120
82121 @ Override
83122 public final String process (final String value ) {
84- String result = value ;
123+ String result ;
85124 try {
86- final java .text .DateFormat inputDateFormat = new SimpleDateFormat (inputFormat );
87- final Date date = inputDateFormat .parse (value );
88- result = java .text .DateFormat .getDateInstance (outputFormat .getFormatId (), outputLocale ).format (date );
125+ final Calendar c = Calendar .getInstance ();
126+ final SimpleDateFormat sdf = new SimpleDateFormat (inputFormat );
127+ c .setTime (sdf .parse (value ));
128+ if (era == Era .BC ) {
129+ c .set (Calendar .ERA , GregorianCalendar .BC );
130+ } else if (era == Era .AD ) {
131+ c .set (Calendar .ERA , GregorianCalendar .AD );
132+ }
133+
134+ final SimpleDateFormat sdfp = (SimpleDateFormat ) java .text .DateFormat .getDateInstance (outputFormat .getFormatId (), outputLocale );
135+ String p = sdfp .toPattern ();
136+ if (c .get (Calendar .ERA ) == GregorianCalendar .BC ) {
137+ p = p .replace ("yyyy" , "yyyy G" );
138+ }
139+
140+ final SimpleDateFormat sdfo = new SimpleDateFormat (p , outputLocale );
141+ result = sdfo .format (c .getTime ());
142+
143+ if (removeLeadingZeros ) {
144+ result = result .replaceAll ("([0]{1,})([0-9]{1,})" , "$2" );
145+ }
146+
89147 } catch (final IllegalArgumentException e ) {
90148 throw new MorphDefException ("The date/time format is not supported." , e );
91- } catch (final ParseException e ) {
92- // Nothing to do
149+ } catch (final Exception e ) {
150+ result = value ;
93151 }
94152 return result ;
95153 }
@@ -102,11 +160,18 @@ public final void setOutputFormat(final DateFormats outputFormat) {
102160 this .outputFormat = outputFormat ;
103161 }
104162
163+ public final void setEra (final Era era ) {
164+ this .era = era ;
165+ }
166+
167+ public final void setRemoveLeadingZeros (final boolean removeLeadingZeros ) {
168+ this .removeLeadingZeros = removeLeadingZeros ;
169+ }
170+
105171 public final void setLanguage (final String language ) {
106172 if (!SUPPORTED_LANGUAGES .contains (language )) {
107173 throw new MorphDefException ("Language '" + language + "' not supported." );
108174 }
109175 this .outputLocale = new Locale (language );
110176 }
111-
112- }
177+ }
0 commit comments