// ============================================================================ // // Copyright (C) 2006-2016 Talend Inc. - www.talend.com // // This source code is available under agreement available at // %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt // // You should have received a copy of the agreement // along with this program; if not, write to Talend SA // 9 rue Pages 92150 Suresnes, France // // ============================================================================ package org.talend.dataquality.converters; import java.time.DateTimeException; import java.time.LocalDate; import java.time.chrono.ChronoLocalDate; import java.time.chrono.Chronology; import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DecimalStyle; import java.time.temporal.TemporalAccessor; import java.util.Locale; import org.apache.log4j.Logger; /** * this class is used for Converting a date from one Chronology to another with the format pattern.<br/> * created by msjian on 2017.1.20 <br/> * <br/> * <p> * for example: the date Chronology type and date string as follows:<br/> * HijrahChronology 1432-09-19<br/> * IsoChronology 2011/08/19<br/> * JapaneseChronology 0023-08-19<br/> * MinguoChronology 0100 08 19<br/> * ThaiBuddhistChronology 2554-08-19<br/> */ public class DateCalendarConverter { private static final Logger LOG = Logger.getLogger(DateCalendarConverter.class); public static final String DEFAULT_INPUT_PATTERN = "yyyy-MM-dd";//$NON-NLS-1$ public static final String DEFAULT_OUTPUT_PATTERN = "yyyy-MM-dd";//$NON-NLS-1$ public static final Locale DEFAULT_OUTPUT_LOCALE = Locale.getDefault(); public static final Locale DEFAULT_INPUT_LOCALE = Locale.getDefault(); /** * the input date text format pattern, default is "yyyy-MM-dd". */ private String inputFormatPattern = DEFAULT_INPUT_PATTERN; /** * the output date text format pattern, default is "yyyy-MM-dd". */ private String outputFormatPattern = DEFAULT_OUTPUT_PATTERN; /** * an optional input Chronology. default is IsoChronology */ private Chronology inputChronologyType = IsoChronology.INSTANCE; /** * an optional output Chronology. default is IsoChronology */ private Chronology outputChronologyType = IsoChronology.INSTANCE; /** * the input DateTimeFormatter(which will be created with inputFormatPattern and inputChronologyType). */ private DateTimeFormatter inputDateTimeFormatter; /** * the output DateTimeFormatter(which will be created with outputFormatPattern and outputChronologyType). */ private DateTimeFormatter outputDateTimeFormatter; public DateCalendarConverter() { this(DEFAULT_INPUT_PATTERN, DEFAULT_OUTPUT_PATTERN, IsoChronology.INSTANCE, IsoChronology.INSTANCE, DEFAULT_INPUT_LOCALE, DEFAULT_OUTPUT_LOCALE); } /** * DateCalendarConverter constructor. * * @param inputChronologyType * @param outputChronologyType */ public DateCalendarConverter(Chronology inputChronologyType, Chronology outputChronologyType) { this(DEFAULT_INPUT_PATTERN, DEFAULT_OUTPUT_PATTERN, inputChronologyType, outputChronologyType, DEFAULT_INPUT_LOCALE, DEFAULT_OUTPUT_LOCALE); } /** * DateCalendarConverter constructor. * * @param inputFormatPattern * @param outputFormatPattern */ public DateCalendarConverter(String inputFormatPattern, String outputFormatPattern) { this(inputFormatPattern, outputFormatPattern, null, null, DEFAULT_INPUT_LOCALE, DEFAULT_OUTPUT_LOCALE); } /** * Convert a date by change the chronology, and use specific locale to manage month as literal. * * @param inputFormatPattern Pattern of the input date to convert. * @param outputFormatPattern Pattern of the conversion result. * @param inputChronologyType Chronology of the input date. * @param outputChronologyType Chronology we want to use to convert the date. * @param inputLocale Locale of the input date, when the date contains month in literal. * @param outputLocale Locale of the converted date when the date contains month in literal. */ public DateCalendarConverter(String inputFormatPattern, String outputFormatPattern, Chronology inputChronologyType, Chronology outputChronologyType, Locale inputLocale, Locale outputLocale) { this(inputFormatPattern, outputFormatPattern, inputChronologyType, outputChronologyType); this.inputDateTimeFormatter = this.inputDateTimeFormatter.withLocale(inputLocale); this.outputDateTimeFormatter = this.outputDateTimeFormatter.withLocale(outputLocale); } /** * DateCalendarConverter constructor. * * @param inputFormatPattern * @param outputFormatPattern * @param inputChronologyType * @param outputChronologyType */ public DateCalendarConverter(String inputFormatPattern, String outputFormatPattern, Chronology inputChronologyType, Chronology outputChronologyType) { this.inputChronologyType = inputChronologyType == null ? IsoChronology.INSTANCE : inputChronologyType; this.outputChronologyType = outputChronologyType == null ? IsoChronology.INSTANCE : outputChronologyType; this.inputFormatPattern = inputFormatPattern == null ? DEFAULT_INPUT_PATTERN : inputFormatPattern; this.outputFormatPattern = outputFormatPattern == null ? DEFAULT_OUTPUT_PATTERN : outputFormatPattern; this.inputDateTimeFormatter = new DateTimeFormatterBuilder().parseLenient().appendPattern(this.inputFormatPattern) .toFormatter().withChronology(this.inputChronologyType) .withDecimalStyle(DecimalStyle.of(Locale.getDefault(Locale.Category.FORMAT))); this.outputDateTimeFormatter = new DateTimeFormatterBuilder().parseLenient().appendPattern(this.outputFormatPattern) .toFormatter().withChronology(this.outputChronologyType) .withDecimalStyle(DecimalStyle.of(Locale.getDefault(Locale.Category.FORMAT))); } /** * Convert an inputFormatPattern date text from inputChronologyType to outputChronologyType with outputFormatPattern. * * @param inputDateStr - the date text need to convert. * @return a outputChronologyType text with the outputFormatPattern. note: if can not parse the dateStr with the * inputFormatPattern, will return "". */ public String convert(String inputDateStr) { if (inputDateStr == null || "".equals(inputDateStr.trim())) { //$NON-NLS-1$ return inputDateStr; } if (inputChronologyType.equals(outputChronologyType) && inputFormatPattern.equals(outputFormatPattern)) { return inputDateStr; } LocalDate inputLocalDate = parseStringToDate(inputDateStr); return formatDateToString(inputLocalDate); } /** * Converts a LocalDate (ISO) value to a ChronoLocalDate date * using the outputChronologyType, and then formats the * ChronoLocalDate to a String using outputDateTimeFormatter. * * @param inputLocalDate - the ISO date to convert and format. * @return String */ protected String formatDateToString(LocalDate inputLocalDate) { if (inputLocalDate != null) { ChronoLocalDate cDate; try { cDate = outputChronologyType.date(inputLocalDate); } catch (DateTimeException ex) { LOG.error(ex, ex); cDate = inputLocalDate; } try { return outputDateTimeFormatter.format(cDate); } catch (DateTimeException ex) { LOG.error(ex, ex); return ""; //$NON-NLS-1$ } } else { return ""; //$NON-NLS-1$ } } /** * Parses a String to a ChronoLocalDate using inputDateTimeFormatter * with inputFormatPattern based on the current Locale and the * provided inputChronologyType, then converts this to a LocalDate (ISO) * value. * * @param inputDateStr - the input date text * @return LocalDate */ protected LocalDate parseStringToDate(String inputDateStr) { try { TemporalAccessor temporal = inputDateTimeFormatter.parse(inputDateStr); ChronoLocalDate cDate = inputChronologyType.date(temporal); return LocalDate.from(cDate); } catch (Exception e) { LOG.error(e, e); return null; } } }