diff --git a/src/main/java/org/javarosa/xform/util/CalendarUtils.java b/src/main/java/org/javarosa/xform/util/CalendarUtils.java index 8ea46de208..79fa4da5e7 100644 --- a/src/main/java/org/javarosa/xform/util/CalendarUtils.java +++ b/src/main/java/org/javarosa/xform/util/CalendarUtils.java @@ -61,6 +61,7 @@ public static String ConvertToEthiopian(Date d, String format) { /* * Nepali calendar system has no discernible cyclic month pattern, so we must manually * enter them here as new calendars are known. + * Calendar source: https://nepalipatro.com.np/calendar * * TODO: Enter month lengths for years beyond 2090 */ @@ -176,16 +177,16 @@ public static String ConvertToEthiopian(Date d, String format) { NEPALI_YEAR_MONTHS.put(2078, new int[]{0, 31, 31, 31, 32, 31, 31, 30, 29, 30, 29, 30, 30}); NEPALI_YEAR_MONTHS.put(2079, new int[]{0, 31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30}); NEPALI_YEAR_MONTHS.put(2080, new int[]{0, 31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 30}); - NEPALI_YEAR_MONTHS.put(2081, new int[]{0, 31, 31, 32, 32, 31, 30, 30, 30, 29, 30, 30, 30}); - NEPALI_YEAR_MONTHS.put(2082, new int[]{0, 30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 30, 30}); - NEPALI_YEAR_MONTHS.put(2083, new int[]{0, 31, 31, 32, 31, 31, 30, 30, 30, 29, 30, 30, 30}); - NEPALI_YEAR_MONTHS.put(2084, new int[]{0, 31, 31, 32, 31, 31, 30, 30, 30, 29, 30, 30, 30}); - NEPALI_YEAR_MONTHS.put(2085, new int[]{0, 31, 32, 31, 32, 30, 31, 30, 30, 29, 30, 30, 30}); - NEPALI_YEAR_MONTHS.put(2086, new int[]{0, 30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 30, 30}); - NEPALI_YEAR_MONTHS.put(2087, new int[]{0, 31, 31, 32, 31, 31, 31, 30, 30, 29, 30, 30, 30}); - NEPALI_YEAR_MONTHS.put(2088, new int[]{0, 30, 31, 32, 32, 30, 31, 30, 30, 29, 30, 30, 30}); - NEPALI_YEAR_MONTHS.put(2089, new int[]{0, 30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 30, 30}); - NEPALI_YEAR_MONTHS.put(2090, new int[]{0, 30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 30, 30}); + NEPALI_YEAR_MONTHS.put(2081, new int[]{0, 31, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31}); + NEPALI_YEAR_MONTHS.put(2082, new int[]{0, 31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30}); + NEPALI_YEAR_MONTHS.put(2083, new int[]{0, 31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30}); + NEPALI_YEAR_MONTHS.put(2084, new int[]{0, 31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31}); + NEPALI_YEAR_MONTHS.put(2085, new int[]{0, 30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31}); + NEPALI_YEAR_MONTHS.put(2086, new int[]{0, 31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30}); + NEPALI_YEAR_MONTHS.put(2087, new int[]{0, 31, 31, 32, 32, 31, 31, 30, 29, 30, 29, 30, 30}); + NEPALI_YEAR_MONTHS.put(2088, new int[]{0, 31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31}); + NEPALI_YEAR_MONTHS.put(2089, new int[]{0, 30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31}); + NEPALI_YEAR_MONTHS.put(2090, new int[]{0, 31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30}); } private static final int MAX_YEAR = 2090; @@ -354,7 +355,7 @@ public static UniversalDate fromMillis(Date date, String timezone) { cd.setTimeZone(DateUtils.timezone()); } long dateInMillis = cd.getTime().getTime(); - DateTimeZone timezoneObject = DateTimeZone.forOffsetMillis(cd.getTimeZone().getRawOffset()); + DateTimeZone timezoneObject = DateTimeZone.forTimeZone(cd.getTimeZone()); return fromMillis(dateInMillis, timezoneObject); } diff --git a/src/test/java/org/javarosa/xform/util/test/CalendarTests.java b/src/test/java/org/javarosa/xform/util/test/CalendarTests.java index 5f92ad89ca..a8c02a2f5a 100644 --- a/src/test/java/org/javarosa/xform/util/test/CalendarTests.java +++ b/src/test/java/org/javarosa/xform/util/test/CalendarTests.java @@ -1,8 +1,13 @@ package org.javarosa.xform.util.test; +import org.javarosa.core.model.utils.DateUtils; +import org.javarosa.core.model.utils.TimezoneProvider; +import org.javarosa.core.services.locale.Localization; +import org.javarosa.core.services.locale.TableLocaleSource; import org.javarosa.xform.util.CalendarUtils; import org.javarosa.xform.util.UniversalDate; import org.joda.time.DateTimeZone; +import org.junit.Before; import org.junit.Test; import java.util.Calendar; @@ -15,6 +20,19 @@ * @author Phillip Mates (pmates@dimagi.com) */ public class CalendarTests { + + @Before + public void configureLocaleForCalendar() { + Localization.getGlobalLocalizerAdvanced().addAvailableLocale("default"); + Localization.setLocale("default"); + TableLocaleSource localeData = new TableLocaleSource(); + localeData.setLocaleMapping("ethiopian_months", + "Mäskäräm,T’ïk’ïmt,Hïdar,Tahsas,T’ïr,Yäkatit,Mägabit,Miyaziya,Gïnbot,Säne,Hämle,Nähäse,P’agume"); + localeData.setLocaleMapping("nepali_months", + "Baishakh,Jestha,Ashadh,Shrawan,Bhadra,Ashwin,Kartik,Mangsir,Poush,Magh,Falgun,Chaitra"); + Localization.getGlobalLocalizerAdvanced().registerLocaleResource("default", localeData); + } + @Test public void testTimesFallOnSameDate() { DateTimeZone nepaliTimeZone = DateTimeZone.forTimeZone(TimeZone.getTimeZone("GMT+05:45")); @@ -25,8 +43,10 @@ public void testTimesFallOnSameDate() { Calendar nepaliBeginningOfDayDate = Calendar.getInstance(nepaliTimeZone.toTimeZone()); nepaliBeginningOfDayDate.set(2007, Calendar.JULY, 7, 0, 0); - UniversalDate middleOfDay = CalendarUtils.fromMillis(nepaliMiddleOfDayDate.getTimeInMillis(), nepaliTimeZone); - UniversalDate beginningOfDay = CalendarUtils.fromMillis(nepaliBeginningOfDayDate.getTimeInMillis(), nepaliTimeZone); + UniversalDate middleOfDay = CalendarUtils.fromMillis(nepaliMiddleOfDayDate.getTimeInMillis(), + nepaliTimeZone); + UniversalDate beginningOfDay = CalendarUtils.fromMillis(nepaliBeginningOfDayDate.getTimeInMillis(), + nepaliTimeZone); assertSameDate(middleOfDay, beginningOfDay); Calendar nepaliEndOfDayDate = Calendar.getInstance(nepaliTimeZone.toTimeZone()); @@ -35,6 +55,33 @@ public void testTimesFallOnSameDate() { assertSameDate(endOfDay, beginningOfDay); } + // millis <=> date is different in every timezone + @Test + public void testConvertToNepaliString() { + MockTimeZoneProvider mockTimeZoneProvider = new MockTimeZoneProvider(TimeZone.getTimeZone("Europe/Madrid")); + DateUtils.setTimezoneProvider(mockTimeZoneProvider); + DateTimeZone timeZone = DateTimeZone.forTimeZone(mockTimeZoneProvider.timeZone); + // this is what Nepali widget uses to calculate the millis from date fields + long millis = CalendarUtils.toMillisFromJavaEpoch(2081, 6, 16, timeZone); + String nepaliDateStr = CalendarUtils.convertToNepaliString(new Date(millis), null); + assertEquals( "16 Ashwin 2081", nepaliDateStr); + + + mockTimeZoneProvider.setTimezone(TimeZone.getTimeZone("Asia/Kathmandu")); + timeZone = DateTimeZone.forTimeZone(mockTimeZoneProvider.timeZone); + millis = CalendarUtils.toMillisFromJavaEpoch(2081, 6, 16, timeZone); + nepaliDateStr = CalendarUtils.convertToNepaliString(new Date(millis), null); + assertEquals( "16 Ashwin 2081", nepaliDateStr); + + + mockTimeZoneProvider.setTimezone(TimeZone.getTimeZone("America/Chicago")); + timeZone = DateTimeZone.forTimeZone(mockTimeZoneProvider.timeZone); + millis = CalendarUtils.toMillisFromJavaEpoch(2081, 6, 16, timeZone); + nepaliDateStr = CalendarUtils.convertToNepaliString(new Date(millis), null); + assertEquals( "16 Ashwin 2081", nepaliDateStr); + DateUtils.resetTimezoneProvider(); + } + private static void assertSameDate(UniversalDate a, UniversalDate b) { assertEquals(a.day, b.day); assertEquals(a.month, b.month); @@ -63,7 +110,8 @@ public void testUnpackingDateInDifferentTimezone() { mexicoCal.set(2007, Calendar.JULY, 7, 18, 46); UniversalDate mexicanDate = CalendarUtils.fromMillis(mexicoCal.getTimeInMillis(), mexicanTimeZone); - long time = CalendarUtils.toMillisFromJavaEpoch(mexicanDate.year, mexicanDate.month, mexicanDate.day, mexicanTimeZone); + long time = CalendarUtils.toMillisFromJavaEpoch(mexicanDate.year, mexicanDate.month, mexicanDate.day, + mexicanTimeZone); UniversalDate rebuiltDateInUsingDifferentTimezone = CalendarUtils.fromMillis(time, nepaliTimeZone); assertSameDate(rebuiltDateInUsingDifferentTimezone, mexicanDate); } @@ -103,4 +151,22 @@ public void serializeUniversalDateViaMillisTest() { deserializedNepaliDate = CalendarUtils.fromMillis(date.getTime(), bostonTimeZone); assertSameDate(nepaliDate, deserializedNepaliDate); } + + private class MockTimeZoneProvider extends TimezoneProvider { + + private TimeZone timeZone; + + public MockTimeZoneProvider(TimeZone timeZone) { + this.timeZone = timeZone; + } + + public void setTimezone(TimeZone timeZone){ + this.timeZone = timeZone; + } + + @Override + public TimeZone getTimezone() { + return timeZone; + } + } }