This is an automated email from the ASF dual-hosted git repository. gk pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/turbine-core.git
commit 29a6875d45436e0bc881475529a8943a6c14ca26 Author: Georg Kallidis <[email protected]> AuthorDate: Mon Nov 6 17:55:30 2023 +0100 Fix Date time service, tool and test. Allow Instant as argument to formatting. Integrate with Turbine Localization Utils and Tool. Activate test for Instant format. --- conf/test/CompleteTurbineResources.properties | 1 - .../localization/DateTimeFormatterInterface.java | 29 ++++- .../localization/DateTimeFormatterService.java | 127 ++++++++++++++++----- .../services/pull/util/DateTimeFormatterTool.java | 85 +++++++++++--- .../localization/DateTimeFormatterServiceTest.java | 105 ++++++++++------- 5 files changed, 258 insertions(+), 89 deletions(-) diff --git a/conf/test/CompleteTurbineResources.properties b/conf/test/CompleteTurbineResources.properties index 9cc1938a..62269e40 100644 --- a/conf/test/CompleteTurbineResources.properties +++ b/conf/test/CompleteTurbineResources.properties @@ -330,7 +330,6 @@ services.UIService.classname = org.apache.turbine.services.ui.TurbineUIService # services.SessionService.classname=org.apache.turbine.services.session.TurbineSessionService services.DateTimeFormatterService.classname= org.apache.turbine.services.localization.DateTimeFormatterService - services.DateTimeFormatterService.earlyInit=true # Turn on the appropriate template service. diff --git a/src/java/org/apache/turbine/services/localization/DateTimeFormatterInterface.java b/src/java/org/apache/turbine/services/localization/DateTimeFormatterInterface.java index 007abe13..8e1c8605 100644 --- a/src/java/org/apache/turbine/services/localization/DateTimeFormatterInterface.java +++ b/src/java/org/apache/turbine/services/localization/DateTimeFormatterInterface.java @@ -1,19 +1,26 @@ package org.apache.turbine.services.localization; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAccessor; import java.util.Locale; public interface DateTimeFormatterInterface { - /** Default date format. find supporrted formats in {@link DateTimeFormatterService} */ - final String DATE_TIME_FORMAT_DEFAULT = "MM/dd/yyyy"; - /** * Property tag for the date format that is to be used for the web - * application. + * application. "tool.dateTool.format" */ - final String DATE_TIME_FORMAT_KEY = "tool.datetimeTool.format"; + final String DATE_TIME_FORMAT_KEY = "datetime.format"; + + final String DATE_TIME_ZONEID_KEY = "datetime.zoneId"; + + final String USE_TURBINE_LOCALE_KEY = "datetime.use.turbine.locale"; + + final String USE_REQUEST_LOCALE_KEY = "tool.use.request.locale"; + + /** Default date format. find supported formats in {@link DateTimeFormatterService} */ + final String DATE_TIME_FORMAT_DEFAULT = "MM/dd/yyyy"; DateTimeFormatter getDefaultFormat(); @@ -48,6 +55,18 @@ public interface DateTimeFormatterInterface { * @return String value of the date */ <T extends TemporalAccessor> String format(T temporalAccessor, String dateFormatString, Locale locale); + + /** + * Formats the given date as a String. + * + * @param the TimeDate date to format + * @param dateFormatString format string to use. See {@link DateTimeFormatter} + * for details. + * @param locale the {@link Locale} + * @param zoneId the {@link ZoneId} + * @return String value of the date + */ + <T extends TemporalAccessor> String format(T temporalAccessor, String dateFormatString, Locale locale, ZoneId zoneId); /** * Maps from an incoming format to an outgoing format {@link DateTimeFormatter}. diff --git a/src/java/org/apache/turbine/services/localization/DateTimeFormatterService.java b/src/java/org/apache/turbine/services/localization/DateTimeFormatterService.java index 8786e43b..4abfcdfc 100644 --- a/src/java/org/apache/turbine/services/localization/DateTimeFormatterService.java +++ b/src/java/org/apache/turbine/services/localization/DateTimeFormatterService.java @@ -1,21 +1,22 @@ package org.apache.turbine.services.localization; +import java.time.DateTimeException; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.TemporalAccessor; +import java.util.Locale; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.turbine.Turbine; import org.apache.turbine.services.TurbineBaseService; - -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -import java.time.temporal.TemporalAccessor; -import java.util.Locale; +import org.apache.turbine.util.LocaleUtils; /** * This service is used to format {@link TemporalAccessor} and - * {@link #map(String, DateTimeFormatter, Locale)} (different falvors) + * {@link #map(String, DateTimeFormatter, Locale)} (different flavors) * objects into strings. * * The methods may throw {@link java.time.temporal.UnsupportedTemporalTypeException} or @@ -31,13 +32,22 @@ public class DateTimeFormatterService public static final String ROLE = DateTimeFormatterService.class.getName(); private String dateTimeFormatPattern = null; - - private DateTimeFormatter defaultFormat = null; + + private DateTimeFormatter dateTimeFormat = null; + + private Locale locale = null; + + private ZoneId zoneId; + + /** + * configura + */ + private boolean useTurbineLocale = true; @Override public DateTimeFormatter getDefaultFormat() { - return defaultFormat; + return dateTimeFormat; } @Override @@ -50,38 +60,71 @@ public class DateTimeFormatterService /** * Initialize the service. * - * the {@link #defaultFormat} from {@link #dateTimeFormatPattern} is initialized with - * the default Locale {@link Locale#getDefault()} and default zone: {@link ZoneId#systemDefault()}. - * + * the {@link #dateTimeFormat} from {@link #dateTimeFormatPattern} is initialized with + * + * <ol> + * <li>{@link Locale}: {@link LocaleUtils#getDefaultLocale()} is used by default. + * It could be overridden setting #USE_TURBINE_LOCALE_KEY to false, the + * the default Locale {@link Locale#getDefault()} is used. + * </li><li>{@link ZoneId}: If #DATE_TIME_ZONEID_KEY is set this {@link ZoneId} + * is used else {@link ZoneId#systemDefault()}. + * </li> + * </ol> */ @Override public void init() { dateTimeFormatPattern = Turbine.getConfiguration() .getString(DATE_TIME_FORMAT_KEY, DATE_TIME_FORMAT_DEFAULT); - defaultFormat = DateTimeFormatter.ofPattern(dateTimeFormatPattern) - .withLocale(Locale.getDefault()).withZone(ZoneId.systemDefault()); + + useTurbineLocale = Turbine.getConfiguration() + .getBoolean(USE_TURBINE_LOCALE_KEY, true); + + Locale locale = (useTurbineLocale && LocaleUtils.getDefaultLocale() != null)? + LocaleUtils.getDefaultLocale() + : Locale.getDefault(); + setLocale(locale); + + String zoneIdStr = Turbine.getConfiguration() + .getString(DATE_TIME_ZONEID_KEY); + ZoneId zoneId = (zoneIdStr != null)? ZoneId.of( zoneIdStr ) : + ZoneId.systemDefault(); + setZoneId(zoneId); + + dateTimeFormat = DateTimeFormatter.ofPattern(dateTimeFormatPattern) + .withLocale(locale).withZone(zoneId); log.info("Initialized DateTimeFormatterService with pattern {}, locale {} and zone {}", - dateTimeFormatPattern, defaultFormat.getLocale(), defaultFormat.getZone()); + dateTimeFormatPattern, dateTimeFormat.getLocale(), + dateTimeFormat.getZone()); setInit(true); } + public ZoneId getZoneId() { + return zoneId; + } + @Override public <T extends TemporalAccessor> String format(T temporalAccessor) { - return defaultFormat.format(temporalAccessor); + return dateTimeFormat.format(temporalAccessor); } @Override public <T extends TemporalAccessor> String format(T temporalAccessor, String dateFormatString) { - return format(temporalAccessor, dateFormatString, null); + return format(temporalAccessor, dateFormatString, null, null); } @Override public <T extends TemporalAccessor> String format(T temporalAccessor, String dateFormatString, Locale locale) { + return format(temporalAccessor, dateFormatString, locale, null); + } + + @Override + public <T extends TemporalAccessor> String format(T temporalAccessor, String dateFormatString, Locale locale, + ZoneId zoneId) { String result = null; if (StringUtils.isEmpty(dateFormatString) || temporalAccessor == null) @@ -90,16 +133,35 @@ public class DateTimeFormatterService } else { - DateTimeFormatter dtf = DateTimeFormatter.ofPattern(dateFormatString); + DateTimeFormatter dtf = + DateTimeFormatter.ofPattern(dateFormatString); if (locale != null) { - dtf.withLocale(locale); + dtf = dtf.withLocale(locale); + } else { + log.warn("adding default local {}", getLocale() ); + dtf = dtf.withLocale( getLocale()); + } + if (zoneId != null) + { + dtf = dtf.withZone(zoneId); + } else { + log.warn("adding default zone {}", getZoneId() ); + dtf = dtf.withZone(getZoneId()); + } + log.warn("try to format {} with {}.", temporalAccessor, dtf ); + try { + result = + dtf.format(temporalAccessor); + } catch(DateTimeException e) { + log.error("An exception with date time formatting was thrown: {}", e); + // check with dtf.toFormat().format(temporalAccessor)? + throw e; } - result = dtf.format(temporalAccessor); } return result; } - + @Override public String map(String src, String outgoingFormatPattern, Locale locale, String incomingFormatPattern) { @@ -134,7 +196,7 @@ public class DateTimeFormatterService } if (incomingFormat == null) { - incomingFormat = defaultFormat; + incomingFormat = dateTimeFormat; } if (incomingFormat.equals( outgoingFormat )) { return ""; @@ -151,18 +213,31 @@ public class DateTimeFormatterService @Override public String mapTo(String src, DateTimeFormatter outgoingFormat) { - return map( src, outgoingFormat, null, defaultFormat ); + return map( src, outgoingFormat, null, dateTimeFormat ); } @Override public String mapFrom(String src, DateTimeFormatter incomingFormat) { - return map( src, defaultFormat, null, incomingFormat ); + return map( src, dateTimeFormat, null, incomingFormat ); } @Override public String map(String src, DateTimeFormatter outgoingFormat, Locale locale) { - return map( src, outgoingFormat, locale, defaultFormat ); + return map( src, outgoingFormat, locale, dateTimeFormat ); } + + public Locale getLocale() { + return locale; + } + + public void setLocale(Locale locale) { + this.locale = locale; + } + + public void setZoneId(ZoneId zoneId) { + this.zoneId = zoneId; + } + } diff --git a/src/java/org/apache/turbine/services/pull/util/DateTimeFormatterTool.java b/src/java/org/apache/turbine/services/pull/util/DateTimeFormatterTool.java index f3bc80de..6ff87deb 100644 --- a/src/java/org/apache/turbine/services/pull/util/DateTimeFormatterTool.java +++ b/src/java/org/apache/turbine/services/pull/util/DateTimeFormatterTool.java @@ -23,29 +23,36 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.temporal.TemporalAccessor; +import java.util.Date; import java.util.Locale; +import org.apache.fulcrum.localization.LocalizationService; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.turbine.Turbine; import org.apache.turbine.annotation.TurbineService; import org.apache.turbine.services.ServiceManager; import org.apache.turbine.services.TurbineServices; import org.apache.turbine.services.localization.DateTimeFormatterInterface; import org.apache.turbine.services.localization.DateTimeFormatterService; -import org.apache.turbine.services.pull.ApplicationTool; +import org.apache.turbine.services.localization.RundataLocalizationService; +import org.apache.turbine.util.RunData; /** * This pull tool is used to format {@link TemporalAccessor} and - * {@link #map(String, DateTimeFormatter, Locale)} (different falvors) + * {@link #map(String, DateTimeFormatter, Locale)} (different flavors) * objects into strings. + * + * This tool extends {@link DateFormatter} to simplify configuration + * and to allow legacy {@link Date} inputs. * * The methods may throw {@link java.time.temporal.UnsupportedTemporalTypeException} or * {@link DateTimeParseException}. * if the source and the target format do not match appropriately. * */ -public class DateTimeFormatterTool - implements ApplicationTool, DateTimeFormatterInterface +public class DateTimeFormatterTool extends DateFormatter + implements DateTimeFormatterInterface { @TurbineService @@ -53,6 +60,14 @@ public class DateTimeFormatterTool private static final Logger log = LogManager.getLogger(DateTimeFormatterTool.class); + /** Fulcrum Localization component */ + @TurbineService + private LocalizationService localizationService; + + protected Locale locale; + + private boolean overrideFromRequestLocale = false; + /** * Initialize the application tool. The data parameter holds a different * type depending on how the tool is being instantiated: @@ -62,22 +77,41 @@ public class DateTimeFormatterTool * <li>For session and persistent tools data will be of type User</li> * </ul> * - * the {@link #defaultFormat} from {@link #dateTimeFormatPattern} with default Locale {@link Locale#getDefault()} and - * Default zone: {@link ZoneId#systemDefault()} - * + * the {@link #defaultFormat} from {@link #dateTimeFormatPattern} + * with {@link DateTimeFormatterService#getLocale()} + * and zoneId {@link DateTimeFormatterService#getZoneId()} is used. + * + * Customizations: + * Locale could be fetched from request, if #USE_REQUEST_LOCALE_KEY is set to + * <code>true</code> (by default it is <code>false</code>.Then it will be retrieved either from + * {@link RundataLocalizationService#getLocale(RunData)} (if set in urbien role configuration) + * or {@link LocalizationService#getLocale(javax.servlet.http.HttpServletRequest)}. + * * @param data initialization data */ @Override public void init(Object data) { - log.info("Initialized DateTimeFormatterTool with service {}", + log.info("Initializing DateTimeFormatterTool with service {}", dtfs); if (dtfs == null) { ServiceManager serviceManager = TurbineServices.getInstance(); dtfs = (DateTimeFormatterService)serviceManager.getService(DateTimeFormatterService.SERVICE_NAME); } + + overrideFromRequestLocale = Turbine.getConfiguration() + .getBoolean(USE_REQUEST_LOCALE_KEY, false); // dtfs should be already initialized + if (overrideFromRequestLocale && data instanceof RunData) + { + // Pull necessary information out of RunData while we have + // a reference to it. + locale = (localizationService instanceof RundataLocalizationService)? + ((RundataLocalizationService)localizationService).getLocale((RunData) data): + localizationService.getLocale(((RunData) data).getRequest()); + log.info("Override {} with request locale {}.", dtfs.getLocale(), locale); + } } public DateTimeFormatterService getDtfs() { @@ -97,11 +131,13 @@ public class DateTimeFormatterTool // empty } + @Override public DateTimeFormatter getDefaultFormat() { return getDtfs().getDefaultFormat(); } + @Override public String getDateTimeFormatPattern() { return getDtfs().getDateTimeFormatPattern(); } @@ -113,44 +149,67 @@ public class DateTimeFormatterTool * @param the {@link TemporalAccessor to format * @return String value of the date */ + @Override public <T extends TemporalAccessor> String format(T temporalAccessor) { return getDtfs().getDefaultFormat().format(temporalAccessor); } + @Override public <T extends TemporalAccessor> String format(T temporalAccessor, String dateFormatString) { - return getDtfs().format(temporalAccessor, dateFormatString, null); + return getDtfs().format(temporalAccessor, dateFormatString); } + @Override public <T extends TemporalAccessor> String format(T temporalAccessor, String dateFormatString, Locale locale) { return getDtfs().format(temporalAccessor, dateFormatString, locale); } + @Override + public <T extends TemporalAccessor> String format(T temporalAccessor, String dateFormatString, Locale locale, + ZoneId zoneId) { + return getDtfs().format(temporalAccessor, dateFormatString, locale, zoneId); + } + + @Override public String map( String src, String outgoingFormatPattern, Locale locale, String incomingFormatPattern) { return getDtfs().map(src, outgoingFormatPattern, locale, incomingFormatPattern); } - public String map( String src, java.time.format.DateTimeFormatter outgoingFormat, Locale locale, - java.time.format.DateTimeFormatter incomingFormat) + @Override + public String map( String src, java.time.format.DateTimeFormatter outgoingFormat, + Locale locale, java.time.format.DateTimeFormatter incomingFormat) { return getDtfs().map(src, outgoingFormat, locale, incomingFormat); } + @Override public String mapTo( String src, DateTimeFormatter outgoingFormat ) { - return getDtfs().map( src, outgoingFormat, null, getDtfs().getDefaultFormat() ); + return getDtfs().map( src, outgoingFormat, getLocale(), getDtfs().getDefaultFormat() ); } + @Override public String mapFrom( String src, DateTimeFormatter incomingFormat ) { - return getDtfs().map( src, getDtfs().getDefaultFormat(), null, incomingFormat ); + return getDtfs().map( src, getDtfs().getDefaultFormat(), getLocale(), incomingFormat ); } + @Override public String map( String src, DateTimeFormatter outgoingFormat, Locale locale ) { return getDtfs().map( src, outgoingFormat, locale, getDtfs().getDefaultFormat() ); } + + public Locale getLocale() { + return locale; + } + + public void setLocale(Locale locale) { + this.locale = locale; + } + } diff --git a/src/test/org/apache/turbine/services/localization/DateTimeFormatterServiceTest.java b/src/test/org/apache/turbine/services/localization/DateTimeFormatterServiceTest.java index af0fd6e0..0f2e50aa 100644 --- a/src/test/org/apache/turbine/services/localization/DateTimeFormatterServiceTest.java +++ b/src/test/org/apache/turbine/services/localization/DateTimeFormatterServiceTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.mock; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; +import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoField; @@ -86,12 +87,11 @@ public class DateTimeFormatterServiceTest extends BaseTestCase { RunDataService runDataService = null; @BeforeAll - public void setup() throws Exception - { + public void setup() throws Exception { // required to initialize defaults tc = new TurbineConfig( - ".", - "/conf/test/CompleteTurbineResources.properties"); + ".", + "/conf/test/CompleteTurbineResources.properties"); tc.initialize(); AnnotationProcessor.process(this); @@ -100,8 +100,7 @@ public class DateTimeFormatterServiceTest extends BaseTestCase { assertNotNull(vs); } - private RunData getRunData() throws Exception - { + private RunData getRunData() throws Exception { ServletConfig config = mock(ServletConfig.class); HttpServletRequest request = getMockRequest(); HttpServletResponse response = mock(HttpServletResponse.class); @@ -112,8 +111,7 @@ public class DateTimeFormatterServiceTest extends BaseTestCase { } @AfterAll - public void tearDown() - { + public void tearDown() { vs.shutdown(); tc.dispose(); } @@ -123,8 +121,7 @@ public class DateTimeFormatterServiceTest extends BaseTestCase { */ @Order(1) @Test - void testTool() throws Exception - { + void testTool() throws Exception { RunData rundata = getRunData(); Context requestContext = vs.getContext(rundata); assertNotNull(requestContext); @@ -133,13 +130,17 @@ public class DateTimeFormatterServiceTest extends BaseTestCase { // taking from request context dateTimeFormatterTool = (DateTimeFormatterTool) requestContext.get("dateTimeFormatter"); assertNotNull(dateTimeFormatterTool); + + assertNotNull(df); } @Order(2) @TestFactory Stream<DynamicNode> testDateTimeFormatterInstances() { // Stream of DateTimeFormatterInterface to check - Stream<DateTimeFormatterInterface> inputStream = Stream.of(df,dateTimeFormatterTool); + Stream<DateTimeFormatterInterface> inputStream = Stream.of( + df, + dateTimeFormatterTool); // Executes tests based on the current input value. return inputStream.map(dtf -> dynamicContainer( "Test " + dtf + " in factory container:", @@ -152,17 +153,17 @@ public class DateTimeFormatterServiceTest extends BaseTestCase { dynamicTest("test mapDateStringEmptyString",() -> mapDateStringEmptyString(dtf)), dynamicTest("test formatDateStringNullFormat",() -> formatDateStringNullFormat(dtf)), dynamicTest("test formatDateStringNullString",() -> formatDateStringNullString(dtf)), - dynamicTest("test formatDateStringEmptyString",() -> formatDateStringEmptyString(dtf)) - )) - ); + dynamicTest("test formatDateStringEmptyString",() -> formatDateStringEmptyString(dtf)), + dynamicTest("test formatInstantString", () -> formatInstantString(dtf)) + ))); // Or return a stream of dynamic tests instead of Dynamic nodes, - // but this requires Function<DateTimeFormatterInterface, String> displayNameGenerator and + // but this requires Function<DateTimeFormatterInterface, String> + // displayNameGenerator and // e.g. ThrowingConsumer<DateTimeFormatterInterface> testExecutor = dtf // return DynamicTest.stream(inputStream, displayNameGenerator, testExecutor); } - void formatDateString(DateTimeFormatterInterface dateTime) - { + void formatDateString(DateTimeFormatterInterface dateTime) { LocalDateTime ldt = LocalDateTime.now(); int day = ldt.get(ChronoField.DAY_OF_MONTH); int month = ldt.get(ChronoField.MONTH_OF_YEAR); // one based @@ -174,12 +175,11 @@ public class DateTimeFormatterServiceTest extends BaseTestCase { String mmddyyyy = "" + monthString + "/" + dayString + "/" + year; - assertEquals(ddmmyyyy, dateTime.format(ldt, "dd/MM/yyyy")); + assertEquals(ddmmyyyy, dateTime.format(ldt, "dd/MM/yyyy")); assertEquals(mmddyyyy, dateTime.format(ldt, "MM/dd/yyyy")); } - void formatZonedDateString(DateTimeFormatterInterface dateTime) - { + void formatZonedDateString(DateTimeFormatterInterface dateTime) { ZonedDateTime zdt = ZonedDateTime.now(); int day = zdt.get(ChronoField.DAY_OF_MONTH); int month = zdt.get(ChronoField.MONTH_OF_YEAR); // one based @@ -201,14 +201,13 @@ public class DateTimeFormatterServiceTest extends BaseTestCase { String zone = zdt.getZone().getId(); /* String offset = */ zdt.getOffset().getId(); // offset formatting not easy matchable, removed - String mmddyyyy = - "" + monthString + "/" + dayString + "/" + year + " " + hourString + ":" + minsString + ":" + secsString + " " + zone; + String mmddyyyy = "" + monthString + "/" + dayString + "/" + year + " " + hourString + ":" + minsString + ":" + + secsString + " " + zone; // zone + offset format, removed offset ZZZ assertEquals(mmddyyyy, dateTime.format(zdt, "MM/dd/yyyy HH:mm:ss VV")); } - void defaultMapFromInstant(DateTimeFormatterInterface dateTime) - { + void defaultMapFromInstant(DateTimeFormatterInterface dateTime) { DateTimeFormatter incomingFormat = DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneId.systemDefault()); // may throws an DateTimeParseException Instant now = Instant.now().truncatedTo(ChronoUnit.MINUTES); @@ -222,11 +221,10 @@ public class DateTimeFormatterServiceTest extends BaseTestCase { String dayString = (day < 10 ? "0" : "") + day; String monthString = (month < 10 ? "0" : "") + month; String mmddyyyy = "" + monthString + "/" + dayString + "/" + year; - assertEquals(mmddyyyy, dateTime.mapFrom(source, incomingFormat)); + assertEquals(mmddyyyy, dateTime.mapFrom(source, incomingFormat)); } - void defaultMapInstant(DateTimeFormatterInterface dateTime) - { + void defaultMapInstant(DateTimeFormatterInterface dateTime) { String source = dateTime.format(Instant.now()); TemporalAccessor dateTimeFromInstant = dateTime.getDefaultFormat().parse(source); @@ -239,36 +237,37 @@ public class DateTimeFormatterServiceTest extends BaseTestCase { String monthString = (month < 10 ? "0" : "") + month; String yyyymmdd = year + "-" + monthString + "-" + dayString; - // caution we are mapping from the DateTimeFormatterTool defaultFormat-pattern without time! + // caution we are mapping from the DateTimeFormatterTool defaultFormat-pattern + // without time! // ISO_DATE_TIME will throw an error: - // java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay + // java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: + // HourOfDay DateTimeFormatter outgoingFormat = DateTimeFormatter.ISO_DATE.withZone(ZoneId.systemDefault()); Assertions.assertEquals(yyyymmdd, dateTime.mapTo(source, outgoingFormat)); outgoingFormat = DateTimeFormatter.ISO_LOCAL_DATE.withZone(ZoneId.systemDefault()); Assertions.assertEquals(yyyymmdd, dateTime.mapTo(source, outgoingFormat)); - // ISO_OFFSET_DATE : Unsupported field: OffsetSeconds + // ISO_OFFSET_DATE : Unsupported field: OffsetSeconds // ISO_INSTANT; Unsupported field: InstantSeconds yyyymmdd = year + monthString + dayString; outgoingFormat = DateTimeFormatter.BASIC_ISO_DATE.withZone(ZoneId.systemDefault()); assertEquals(yyyymmdd, dateTime.mapTo(source, outgoingFormat)); } + /* * Class under test for String format(null, String) */ - void mapDateStringNullString(DateTimeFormatterInterface dateTime) - { + void mapDateStringNullString(DateTimeFormatterInterface dateTime) { DateTimeFormatter outgoingFormat = DateTimeFormatter.ISO_INSTANT; Assertions.assertEquals("", - dateTime.mapFrom(null, outgoingFormat), "null argument should produce an empty String"); + dateTime.mapFrom(null, outgoingFormat), "null argument should produce an empty String"); } /* * Class under test for String format(Date, "") */ - void mapDateStringEmptyString(DateTimeFormatterInterface dateTime ) - { + void mapDateStringEmptyString(DateTimeFormatterInterface dateTime) { Instant today = Instant.now(); String todayFormatted = df.format(today); Assertions.assertEquals("", @@ -278,31 +277,49 @@ public class DateTimeFormatterServiceTest extends BaseTestCase { /* * Class under test for String format(null, String) */ - void formatDateStringNullString(DateTimeFormatterInterface dateTime ) - { + void formatDateStringNullString(DateTimeFormatterInterface dateTime) { Assertions.assertEquals("", - dateTime.format(null, "MM/dd/xyyyy"), "null argument should produce an empty String"); + dateTime.format(null, "MM/dd/xyyyy"), "null argument should produce an empty String"); } /* * Class under test for String format(Date, "") */ - void formatDateStringEmptyString(DateTimeFormatterInterface dateTime) - { + void formatDateStringEmptyString(DateTimeFormatterInterface dateTime) { Instant today = Instant.now(); Assertions.assertEquals("", - dateTime.format(today, ""), "Empty pattern should produce empty String"); + dateTime.format(today, ""), "Empty pattern should produce empty String"); } /* * Class under test for String format(Date, "") */ - void formatDateStringNullFormat(DateTimeFormatterInterface dateTime) - { + void formatDateStringNullFormat(DateTimeFormatterInterface dateTime) { Instant today = Instant.now(); Assertions.assertEquals("", - dateTime.format(today, null), "null pattern should produce empty String"); + dateTime.format(today, null), "null pattern should produce empty String"); + } + + void formatInstantString(DateTimeFormatterInterface dateTime) { + + ZonedDateTime zonedToday = ZonedDateTime.now(ZoneOffset.UTC.normalized()); + int day = zonedToday.get(ChronoField.DAY_OF_MONTH); + int month = zonedToday.get(ChronoField.MONTH_OF_YEAR); // one based + int year = zonedToday.get(ChronoField.YEAR); + + String dayString = (day < 10 ? "0" : "") + day; + String monthString = (month < 10 ? "0" : "") + month; + String ddmmyyyy = dayString + "/" + monthString + "/" + year; + String mmddyyyy = "" + monthString + "/" + dayString + "/" + year; + assertNotNull(ddmmyyyy); + assertNotNull(mmddyyyy); + + Instant today = Instant.now(); + assertNotNull(dateTime.format(today, "dd/MM/yyyy")); + assertNotNull(dateTime.format(today, "MM")); + assertEquals(ddmmyyyy, dateTime.format(today, "dd/MM/yyyy")); + assertEquals(mmddyyyy, dateTime.format(today, "MM/dd/yyyy")); } }
