Wednesday, 21 November 2012

clock changing - Is this a Long, Short or a Normal day

Time is always a thorn in the side of developers.

In my latest project I needed to know the number of hours in a day and I could find no easy method on existing classes to determine if the day was a clock change day. I thought the great Joda date time classes would have helped but I could not find the one I needed so I wrote this.

 public enum ClockChangeInfo {  
  LONG_DAY(90000000, 25), SHORT_DAY(82800000, 23), NORMAL_DAY(86400000, 24), INDETERMINATE(0, 0);  
  private int mMsecs;  
  private int mHrs;  
  private static final Map<Integer, ClockChangeInfo> MSEC = new HashMap<Integer, ClockChangeInfo>();  
  static {  
   for (ClockChangeInfo cci : values()) {  
    MSEC.put(new Integer(cci.mMsecs), cci);  
   }  
  }  
  ClockChangeInfo(int aMsecs, int aHrs) {  
   mMsecs = aMsecs;  
   mHrs = aHrs;  
  }  
  public int getHrs(ClockChangeInfo aCci) {  
   return aCci.mHrs;  
  }  
  public static ClockChangeInfo getDayType(DateMidnight dateToCheck) {  
   DateMidnight nextDay = dateToCheck.plusDays(1);  
   //this is a safe convert as it is only for day(n) - day(n-1)  
   Integer millis = (int)(nextDay.getMillis() - dateToCheck.getMillis());  
   ClockChangeInfo cci = MSEC.get(millis);  
   if (cci == null) {  
    return INDETERMINATE;  
   }  
   return cci;  
  }  
 }  

 public class ClockChangeUtil {  
  public static ClockChangeInfo getDayType(DateMidnight dateToCheck) {  
   return ClockChangeInfo.getDayType((dateToCheck));  
  }  
  public static int getNumHoursInDay(DateMidnight dateToCheck) {  
   ClockChangeInfo dayType = ClockChangeUtil.getDayType(dateToCheck);  
   return dayType.getHrs(dayType);  
  }  
  public static int getNumHalfHoursINMonthSoFar(DateMidnight dateToCheck) {  
   int numHours = 0;  
   int day = dateToCheck.getDayOfMonth();  
   if (day == 1) {  
    return 0;  
   }  
   DateMidnight dm = dateToCheck.minusDays(1);  
   do {  
    numHours += getNumHoursInDay(dm);  
    dm = dm.minusDays(1);  
    day--;  
   } while (day > 1);  
   return numHours * 2;  
  }  
 }  


and some test methods for it. NB these are UK based.


 public class ClockChangeUtilUnitTest  
 {  
  @Test  
  public void test_isLongDay() throws Exception  
  {  
   DateMidnight dm28 = new DateMidnight(2011, 10, 28);  
   DateMidnight dm29 = new DateMidnight(2011, 10, 29);  
   DateMidnight dm30 = new DateMidnight(2011, 10, 30);  
   DateMidnight dm31 = new DateMidnight(2011, 10, 31);   
   assertEquals(ClockChangeInfo.NORMAL_DAY, ClockChangeUtil.getDayType(dm28));  
   assertEquals(ClockChangeInfo.NORMAL_DAY, ClockChangeUtil.getDayType(dm29));  
   assertEquals(ClockChangeInfo.LONG_DAY, ClockChangeUtil.getDayType(dm30));  
   assertEquals(ClockChangeInfo.NORMAL_DAY, ClockChangeUtil.getDayType(dm31));  
  }  
  @Test  
  public void test_isShortDay() throws Exception  
  {  
   DateMidnight dm26 = new DateMidnight(2011, 3, 26);  
   DateMidnight dm27 = new DateMidnight(2011, 3, 27);  
   DateMidnight dm28 = new DateMidnight(2011, 3, 28);  
   DateMidnight dm29 = new DateMidnight(2011, 3, 29);  
   assertEquals(ClockChangeInfo.NORMAL_DAY, ClockChangeUtil.getDayType(dm26));  
   assertEquals(ClockChangeInfo.SHORT_DAY, ClockChangeUtil.getDayType(dm27));  
   assertEquals(ClockChangeInfo.NORMAL_DAY, ClockChangeUtil.getDayType(dm28));  
   assertEquals(ClockChangeInfo.NORMAL_DAY, ClockChangeUtil.getDayType(dm29));  
  }  
  @Test  
  public void testClockChange() throws Exception  
  {  
   long millisInANormalDay = 24 * 60 * 60 * 1000;  
   long millisInALongDay = 25 * 60 * 60 * 1000;  
   DateMidnight dm28 = new DateMidnight(2011, 10, 28);  
   DateMidnight dm29 = new DateMidnight(2011, 10, 29);  
   DateMidnight dm30 = new DateMidnight(2011, 10, 30);  
   DateMidnight dm31 = new DateMidnight(2011, 10, 31);  
   assertEquals(millisInANormalDay, dm29.getMillis() - dm28.getMillis());  
   assertEquals(millisInANormalDay, dm30.getMillis() - dm29.getMillis());  
   assertEquals(millisInALongDay, dm31.getMillis() - dm30.getMillis());  
   DateTime dt28 = new DateTime(dm28);  
   DateTime dt29 = new DateTime(dm29);  
   DateTime dt30 = new DateTime(dm30);  
   DateTime dt31 = new DateTime(dm31);  
   assertEquals(millisInANormalDay, dt29.getMillis() - dt28.getMillis());  
   assertEquals(millisInANormalDay, dt30.getMillis() - dt29.getMillis());  
   assertEquals(millisInALongDay, dt31.getMillis() - dt30.getMillis());  
   assertTrue(dt28.getZone().equals(dt29.getZone()));  
   assertTrue(dt28.getZone().equals(dt30.getZone()));  
   assertTrue(dt28.getZone().equals(dt31.getZone()));  
  }  
  @Test  
  public void test_getNumHoursInDay() throws Exception  
  {  
   DateMidnight dm26 = new DateMidnight(2011, 3, 26);  
   DateMidnight dm27 = new DateMidnight(2011, 3, 27);  
   DateMidnight dm28 = new DateMidnight(2011, 3, 28);  
   DateMidnight dm29 = new DateMidnight(2011, 3, 29);  
   assertEquals(24, ClockChangeUtil.getNumHoursInDay(dm26));  
   assertEquals(23, ClockChangeUtil.getNumHoursInDay(dm27));  
   assertEquals(24, ClockChangeUtil.getNumHoursInDay(dm28));  
   assertEquals(24, ClockChangeUtil.getNumHoursInDay(dm29));  
  }  
 }  





No comments: