package org.marketcetera.marketdata; import static org.junit.Assert.assertEquals; import static org.marketcetera.marketdata.DateUtils.*; import static org.marketcetera.marketdata.Messages.INVALID_DATE; import java.text.DateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormatter; import org.junit.BeforeClass; import org.junit.Test; import org.marketcetera.module.ExpectedFailure; /* $License$ */ /** * Tests {@link DateUtil}. * * @author <a href="mailto:colin@marketcetera.com">Colin DuPlantis</a> * @version $Id: DateUtilsTest.java 16154 2012-07-14 16:34:05Z colin $ * @since 1.5.0 */ public class DateUtilsTest { private static DateFormat testDateFormat; /** * Initialization that needs to be run once for all tests. */ @BeforeClass public static void runOnce() { testDateFormat = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, Locale.US); testDateFormat.setTimeZone(TimeZone.getTimeZone("America/New_York")); } /** * Tests {@link DateUtils#stringToDate(String)}. * * <p>Note that the tests are intentionally not exhaustive as the vast number of permutations * would far exceed time available to run them. Additionally, since the parsing of the dates * is actually handled by an external library, to a certain extent, the behavior can be assumed * to be valid. * * @throws Exception if an error occurs */ @Test public void stringToDate() throws Exception { // test some obvious stinkers new ExpectedFailure<MarketDataRequestException>(INVALID_DATE) { protected void run() throws Exception { DateUtils.stringToDate(null); } }; new ExpectedFailure<MarketDataRequestException>(INVALID_DATE) { protected void run() throws Exception { DateUtils.stringToDate(""); } }; // now build a few (incomplete) lists of invalid and valid components String[] invalidDateStrings = new String[] { "", "1", "11", "111", "1111", "11111", "111111", "x111111", "-123-4-5", "00000000", "20091301", "20090132", "19960230", "21000229" }; // haha, 2100 will *not* be a leap year String[] invalidTimeStrings = new String[] { "", "1", "11", "111", "-123", "-1-2", "12345", "1234567", "12345678", "2500", "2461", "240061" }; String[] invalidTimeZoneStrings = new String[] { "X", "ZZ", "/1000", "+2500", "-0061" }; String[] validDateStrings = new String[] { "00000101", "20040229", "99990531" }; String[] validTimeStrings = new String[] { "0000", "000000", "000000000" }; String[] validTimeZoneStrings = new String[] { "Z", "z", "+0000", "-1000", "+0530" }; // iterate over the failure cases for(int dateCounter=0;dateCounter<invalidDateStrings.length;dateCounter++) { for(int timeCounter=0;timeCounter<invalidTimeStrings.length;timeCounter++) { for(int tzCounter=0;tzCounter<invalidTimeZoneStrings.length;tzCounter++) { final String dateString = invalidDateStrings[dateCounter]; final String timeString = invalidTimeStrings[timeCounter]; final String tzString = invalidTimeZoneStrings[tzCounter]; // date alone new ExpectedFailure<MarketDataRequestException>(INVALID_DATE) { protected void run() throws Exception { DateUtils.stringToDate(dateString); } }; // date & tz new ExpectedFailure<MarketDataRequestException>(INVALID_DATE) { protected void run() throws Exception { DateUtils.stringToDate(String.format("%s%s", dateString, tzString)); } }; // date & time new ExpectedFailure<MarketDataRequestException>(INVALID_DATE) { protected void run() throws Exception { DateUtils.stringToDate(String.format("%sT%s", dateString, timeString)); } }; // date, time, & tz new ExpectedFailure<MarketDataRequestException>(INVALID_DATE) { protected void run() throws Exception { DateUtils.stringToDate(String.format("%sT%s%s", dateString, timeString, tzString)); } }; } } } // iterate over the success cases (success is measured by the ability to return a date rather than throw an exception: // calculating the expected dates without using the library that already calculates them would require significant // complexity. for(int dateCounter=0;dateCounter<validDateStrings.length;dateCounter++) { for(int timeCounter=0;timeCounter<validTimeStrings.length;timeCounter++) { for(int tzCounter=0;tzCounter<invalidTimeZoneStrings.length;tzCounter++) { String dateString = validDateStrings[dateCounter]; String timeString = validTimeStrings[timeCounter]; String tzString = validTimeZoneStrings[tzCounter]; // date only DateUtils.stringToDate(dateString); // date & tz DateUtils.stringToDate(String.format("%s%s", dateString, tzString)); // date & time DateUtils.stringToDate(String.format("%sT%s", dateString, timeString)); // date, time, & tz DateUtils.stringToDate(String.format("%sT%s%s", dateString, timeString, tzString)); } } } // check a few dates // UTC date doDateTest("20090319T120000000Z", "20090319T120000000Z", "Thursday, March 19, 2009 8:00:00 AM EDT"); // PST date doDateTest("19700319T0800-0800", "19700319T160000000Z", "Thursday, March 19, 1970 11:00:00 AM EST"); // no TZ (assumed to be UTC) doDateTest("19880319T0000", "19880319T000000000Z", "Friday, March 18, 1988 7:00:00 PM EST"); } /** * Tests that specifying a particular format returns the expected result. * * @throws Exception if an error occurs */ @Test public void specificFormats() throws Exception { DateTimeFormatter[] formats = new DateTimeFormatter[] { MILLIS_WITH_TZ,MILLIS,SECONDS_WITH_TZ,SECONDS,MINUTES_WITH_TZ,MINUTES,DAYS_WITH_TZ,DAYS }; new ExpectedFailure<NullPointerException>() { protected void run() throws Exception { DateUtils.dateToString(new Date(), null); } }; // take a date and make sure it comes out correctly when asking for a specific format Date testDate = new Date(); for(DateTimeFormatter format : formats) { assertEquals(format.print(new DateTime(testDate)), DateUtils.dateToString(testDate, format)); } } /** * Verifies the given ISO 8601 date is parsed correctly. * * @param inDateToTest a <code>String</code> value containing a valid ISO 8601 date as defined in * {@link DateUtils#stringToDate(String)} * @param inExpectedUTCDate a <code>String</code> value containing the given test date expressed in * ISO 8601 to millisecond precision in UTC * @param inExpectedEasternDate a <code>String</code> value containing the given test date expressed * in {@link DateFormat#FULL} format in US Eastern time * @throws Exception if an error occurs */ private static void doDateTest(String inDateToTest, String inExpectedUTCDate, String inExpectedEasternDate) throws Exception { Date date = DateUtils.stringToDate(inDateToTest); assertEquals(inExpectedUTCDate, DateUtils.dateToString(date)); assertEquals(testDateFormat.parse(inExpectedEasternDate), date); } }