1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; 4 import static android.os.Build.VERSION_CODES.KITKAT; 5 import static org.assertj.core.api.Assertions.assertThat; 6 import static org.junit.Assert.assertEquals; 7 import static org.junit.Assert.assertFalse; 8 import static org.junit.Assert.assertNotNull; 9 import static org.junit.Assert.assertTrue; 10 11 import android.os.SystemClock; 12 import android.text.format.Time; 13 import android.util.TimeFormatException; 14 import java.util.Arrays; 15 import java.util.TimeZone; 16 import org.junit.After; 17 import org.junit.Test; 18 import org.junit.runner.RunWith; 19 import org.robolectric.RobolectricTestRunner; 20 import org.robolectric.annotation.Config; 21 22 @RunWith(RobolectricTestRunner.class) 23 @Config(minSdk = JELLY_BEAN_MR2) 24 public class ShadowTimeTest { 25 private static final TimeZone DEFAULT_TIMEZONE = TimeZone.getDefault(); 26 27 @After 28 public void tearDown() { 29 // Just in case any of the tests mess with the system-wide 30 // default time zone, make sure we've set it back to what 31 // it should be. 32 TimeZone.setDefault(DEFAULT_TIMEZONE); 33 } 34 35 @Test 36 public void shouldSetToNow() throws Exception { 37 Time t = new Time(); 38 SystemClock.setCurrentTimeMillis(1000); 39 t.setToNow(); 40 assertThat(t.toMillis(false)).isEqualTo(1000); 41 } 42 43 @Test 44 public void shouldHaveNoArgsConstructor() throws Exception { 45 Time t = new Time(); 46 assertNotNull(t.timezone); 47 } 48 49 @Test 50 public void shouldHaveCopyConstructor() throws Exception { 51 Time t = new Time(); 52 t.setToNow(); 53 Time t2 = new Time(t); 54 assertEquals(t.timezone, t2.timezone); 55 assertEquals(t.year, t2.year); 56 assertEquals(t.month, t2.month); 57 assertEquals(t.monthDay, t2.monthDay); 58 assertEquals(t.hour, t2.hour); 59 assertEquals(t.minute, t2.minute); 60 assertEquals(t.second, t2.second); 61 } 62 63 @Test 64 public void shouldHaveSetTime() throws Exception { 65 Time t = new Time(); 66 t.setToNow(); 67 Time t2 = new Time(); 68 t2.set(t); 69 assertEquals(t.timezone, t2.timezone); 70 assertEquals(t.year, t2.year); 71 assertEquals(t.month, t2.month); 72 assertEquals(t.monthDay, t2.monthDay); 73 assertEquals(t.hour, t2.hour); 74 assertEquals(t.minute, t2.minute); 75 assertEquals(t.second, t2.second); 76 } 77 78 @Test 79 public void shouldHaveSet3Args() throws Exception { 80 Time t = new Time(); 81 t.set(1, 1, 2000); 82 assertEquals(t.year, 2000); 83 assertEquals(t.month, 1); 84 assertEquals(t.monthDay, 1); 85 } 86 87 @Test 88 public void shouldHaveSet6Args() throws Exception { 89 Time t = new Time(); 90 t.set(1, 1, 1, 1, 1, 2000); 91 assertEquals(t.year, 2000); 92 assertEquals(t.month, 1); 93 assertEquals(t.monthDay, 1); 94 assertEquals(t.second, 1); 95 assertEquals(t.minute, 1); 96 assertEquals(t.hour, 1); 97 } 98 99 @Test 100 public void shouldHaveTimeZoneConstructor() throws Exception { 101 Time t = new Time("UTC"); 102 assertEquals(t.timezone, "UTC"); 103 } 104 105 @Test 106 public void shouldClear() throws Exception { 107 Time t = new Time(); 108 t.setToNow(); 109 t.clear("UTC"); 110 assertEquals("UTC", t.timezone); 111 assertEquals(0, t.year); 112 assertEquals(0, t.month); 113 assertEquals(0, t.monthDay); 114 assertEquals(0, t.hour); 115 assertEquals(0, t.minute); 116 assertEquals(0, t.second); 117 assertEquals(0, t.weekDay); 118 assertEquals(0, t.yearDay); 119 assertEquals(0, t.gmtoff); 120 assertEquals(-1, t.isDst); 121 } 122 123 @Test 124 public void shouldHaveToMillis() throws Exception { 125 Time t = new Time(); 126 t.set(86400 * 1000); 127 assertEquals(86400 * 1000, t.toMillis(false)); 128 } 129 130 @Test 131 public void shouldHaveCurrentTimeZone() throws Exception { 132 assertNotNull(Time.getCurrentTimezone()); 133 } 134 135 @Test 136 public void shouldSwitchTimeZones() throws Exception { 137 Time t = new Time("UTC"); 138 139 t.set(1414213562373L); 140 assertThat(t.timezone).isEqualTo("UTC"); 141 assertThat(t.gmtoff).isEqualTo(0); 142 assertThat(t.format3339(false)).isEqualTo("2014-10-25T05:06:02.000Z"); 143 144 t.switchTimezone("America/New_York"); 145 assertThat(t.format3339(false)).isEqualTo("2014-10-25T01:06:02.000-04:00"); 146 assertThat(t.timezone).isEqualTo("America/New_York"); 147 assertThat(t.gmtoff).isEqualTo(-14400L); 148 assertThat(t.toMillis(true)).isEqualTo(1414213562000L); 149 } 150 151 @Test 152 public void shouldHaveCompareAndBeforeAfter() throws Exception { 153 Time a = new Time(); 154 Time b = new Time(); 155 156 assertThat(Time.compare(a, b)).isEqualTo(0); 157 assertThat(a.before(b)).isFalse(); 158 assertThat(a.after(b)).isFalse(); 159 160 a.year = 2000; 161 assertThat(Time.compare(a, b)).isPositive(); 162 assertThat(a.after(b)).isTrue(); 163 assertThat(b.before(a)).isTrue(); 164 165 b.year = 2001; 166 assertThat(Time.compare(a, b)).isNegative(); 167 assertThat(b.after(a)).isTrue(); 168 assertThat(a.before(b)).isTrue(); 169 } 170 171 @Test 172 public void shouldHaveParse() throws Exception { 173 Time t = new Time("Europe/Berlin"); 174 assertFalse(t.parse("20081013T160000")); 175 assertEquals(2008, t.year); 176 assertEquals(9, t.month); 177 assertEquals(13, t.monthDay); 178 assertEquals(16, t.hour); 179 assertEquals(0, t.minute); 180 assertEquals(0, t.second); 181 182 assertTrue(t.parse("20081013T160000Z")); 183 assertEquals(2008, t.year); 184 assertEquals(9, t.month); 185 assertEquals(13, t.monthDay); 186 assertEquals(16, t.hour); 187 assertEquals(0, t.minute); 188 assertEquals(0, t.second); 189 } 190 191 @Test 192 public void shouldParseRfc3339() { 193 for (String tz : Arrays.asList("Europe/Berlin", "America/Los Angeles", "Australia/Adelaide")) { 194 String desc = "Eval when local timezone is " + tz; 195 TimeZone.setDefault(TimeZone.getTimeZone(tz)); 196 197 Time t = new Time("Europe/Berlin"); 198 assertTrue(desc, t.parse3339("2008-10-13T16:30:50Z")); 199 assertEquals(desc, 2008, t.year); 200 assertEquals(desc, 9, t.month); 201 assertEquals(desc, 13, t.monthDay); 202 assertEquals(desc, 16, t.hour); 203 assertEquals(desc, 30, t.minute); 204 assertEquals(desc, 50, t.second); 205 assertEquals(desc, "UTC", t.timezone); 206 assertFalse(desc, t.allDay); 207 208 t = new Time("Europe/Berlin"); 209 assertTrue(desc, t.parse3339("2008-10-13T16:30:50.000+07:00")); 210 assertEquals(desc, 2008, t.year); 211 assertEquals(desc, 9, t.month); 212 assertEquals(desc, 13, t.monthDay); 213 assertEquals(desc, 9, t.hour); 214 assertEquals(desc, 30, t.minute); 215 assertEquals(desc, 50, t.second); 216 assertEquals(desc, "UTC", t.timezone); 217 assertFalse(desc, t.allDay); 218 219 t = new Time("Europe/Berlin"); 220 assertFalse(desc, t.parse3339("2008-10-13")); 221 assertEquals(desc, 2008, t.year); 222 assertEquals(desc, 9, t.month); 223 assertEquals(desc, 13, t.monthDay); 224 assertEquals(desc, 0, t.hour); 225 assertEquals(desc, 0, t.minute); 226 assertEquals(desc, 0, t.second); 227 assertEquals(desc, "Europe/Berlin", t.timezone); 228 assertTrue(desc, t.allDay); 229 } 230 } 231 232 @Test 233 @Config(maxSdk = KITKAT) 234 // this fails on LOLLIPOP+; is the shadow impl of parse3339 correct for pre-LOLLIPOP? 235 public void shouldParseRfc3339_withQuestionableFormat() { 236 for (String tz : Arrays.asList("Europe/Berlin", "America/Los Angeles", "Australia/Adelaide")) { 237 String desc = "Eval when local timezone is " + tz; 238 TimeZone.setDefault(TimeZone.getTimeZone(tz)); 239 240 Time t = new Time("Europe/Berlin"); 241 assertTrue(desc, t.parse3339("2008-10-13T16:30:50.999-03")); 242 assertEquals(desc, 2008, t.year); 243 assertEquals(desc, 9, t.month); 244 assertEquals(desc, 13, t.monthDay); 245 assertEquals(desc, 19, t.hour); 246 assertEquals(desc, 30, t.minute); 247 assertEquals(desc, 50, t.second); 248 assertEquals(desc, "UTC", t.timezone); 249 assertFalse(desc, t.allDay); 250 } 251 } 252 253 @Test(expected = TimeFormatException.class) 254 public void shouldThrowTimeFormatException() throws Exception { 255 Time t = new Time(); 256 t.parse("BLARGH"); 257 } 258 259 @Test 260 public void shouldHaveParseShort() throws Exception { 261 Time t = new Time(); 262 t.parse("20081013"); 263 assertEquals(2008, t.year); 264 assertEquals(9, t.month); 265 assertEquals(13, t.monthDay); 266 assertEquals(0, t.hour); 267 assertEquals(0, t.minute); 268 assertEquals(0, t.second); 269 } 270 271 @Test 272 public void shouldFormat() throws Exception { 273 Time t = new Time(Time.TIMEZONE_UTC); 274 t.set(3600000L); 275 276 assertEquals("Hello epoch 01 1970 01", t.format("Hello epoch %d %Y %d")); 277 assertEquals("Hello epoch 1:00 AM", t.format("Hello epoch %l:%M %p")); 278 } 279 280 @Test 281 public void shouldFormatAndroidStrings() throws Exception { 282 Time t = new Time("UTC"); 283 // NOTE: month is zero-based. 284 t.set(12, 13, 14, 8, 8, 1987); 285 286 assertEquals(1987, t.year); 287 assertEquals(8, t.month); 288 assertEquals(8, t.monthDay); 289 assertEquals(14, t.hour); 290 assertEquals(13, t.minute); 291 assertEquals(12, t.second); 292 293 // ICS 294 295 // date_and_time 296 assertEquals( 297 "Sep 8, 1987, 2:13:12 PM", 298 t.format("%b %-e, %Y, %-l:%M:%S %p")); 299 300 // hour_minute_cap_ampm 301 assertEquals( 302 "2:13PM", 303 t.format("%-l:%M%^p")); 304 } 305 306 @Test 307 public void shouldFormatAllFormats() throws Exception { 308 Time t = new Time("Asia/Tokyo"); 309 t.set(1407496560000L); 310 311 // Don't check for %c (the docs state not to use it, and it doesn't work correctly). 312 assertEquals("Fri", t.format("%a")); 313 assertEquals("Friday", t.format("%A")); 314 assertEquals("Aug", t.format("%b")); 315 assertEquals("August", t.format("%B")); 316 assertEquals("20", t.format("%C")); 317 assertEquals("08", t.format("%d")); 318 assertEquals("08/08/14", t.format("%D")); 319 assertEquals(" 8", t.format("%e")); 320 assertEquals("2014-08-08", t.format("%F")); 321 assertEquals("14", t.format("%g")); 322 assertEquals("2014", t.format("%G")); 323 assertEquals("Aug", t.format("%h")); 324 assertEquals("20", t.format("%H")); 325 assertEquals("08", t.format("%I")); 326 assertEquals("220", t.format("%j")); 327 assertEquals("20", t.format("%k")); 328 assertEquals(" 8", t.format("%l")); 329 assertEquals("08", t.format("%m")); 330 assertEquals("16", t.format("%M")); 331 assertEquals("\n", t.format("%n")); 332 assertEquals("PM", t.format("%p")); 333 assertEquals("pm", t.format("%P")); 334 assertEquals("08:16:00 PM", t.format("%r")); 335 assertEquals("20:16", t.format("%R")); 336 assertEquals("1407496560", t.format("%s")); 337 assertEquals("00", t.format("%S")); 338 assertEquals("\t", t.format("%t")); 339 assertEquals("20:16:00", t.format("%T")); 340 assertEquals("5", t.format("%u")); 341 assertEquals("32", t.format("%V")); 342 assertEquals("5", t.format("%w")); 343 assertEquals("14", t.format("%y")); 344 assertEquals("2014", t.format("%Y")); 345 assertEquals("+0900", t.format("%z")); 346 assertEquals("JST", t.format("%Z")); 347 348 // Padding. 349 assertEquals("8", t.format("%-l")); 350 assertEquals(" 8", t.format("%_l")); 351 assertEquals("08", t.format("%0l")); 352 353 // Escape. 354 assertEquals("%", t.format("%%")); 355 } 356 357 @Test 358 @Config(maxSdk = KITKAT) 359 // these fail on LOLLIPOP+; is the shadow impl of format correct for pre-LOLLIPOP? 360 public void shouldFormatAllFormats_withQuestionableResults() throws Exception { 361 Time t = new Time("Asia/Tokyo"); 362 t.set(1407496560000L); 363 364 assertEquals("08/08/2014", t.format("%x")); 365 assertEquals("08:16:00 PM", t.format("%X")); 366 367 // Case. 368 assertEquals("PM", t.format("%^P")); 369 assertEquals("PM", t.format("%#P")); 370 } 371 372 @Test 373 public void shouldFormat2445() throws Exception { 374 Time t = new Time(); 375 t.timezone = "PST"; 376 assertEquals("19700101T000000", t.format2445()); 377 378 t.timezone = Time.TIMEZONE_UTC; 379 //2445 formatted date should hava a Z postfix 380 assertEquals("19700101T000000Z",t.format2445()); 381 } 382 383 @Test 384 public void shouldFormat3339() throws Exception { 385 Time t = new Time("Europe/Berlin"); 386 assertEquals("1970-01-01T00:00:00.000+00:00", t.format3339(false)); 387 assertEquals("1970-01-01", t.format3339(true)); 388 } 389 390 @Test 391 public void testIsEpoch() throws Exception { 392 Time t = new Time(); 393 boolean isEpoch = Time.isEpoch(t); 394 assertEquals(true, isEpoch); 395 } 396 397 @Test 398 public void testGetJulianDay() throws Exception { 399 Time time = new Time(); 400 401 time.set(0, 0, 0, 12, 5, 2008); 402 time.timezone = "Australia/Sydney"; 403 long millis = time.normalize(true); 404 405 // This is the Julian day for 12am for this day of the year 406 int julianDay = Time.getJulianDay(millis, time.gmtoff); 407 408 // Change the time during the day and check that we get the same 409 // Julian day. 410 for (int hour = 0; hour < 24; hour++) { 411 for (int minute = 0; minute < 60; minute += 15) { 412 time.set(0, minute, hour, 12, 5, 2008); 413 millis = time.normalize(true); 414 int day = Time.getJulianDay(millis, time.gmtoff); 415 416 assertEquals(day, julianDay); 417 } 418 } 419 } 420 421 @Test 422 public void testSetJulianDay() throws Exception { 423 Time time = new Time(); 424 time.set(0, 0, 0, 12, 5, 2008); 425 time.timezone = "Australia/Sydney"; 426 long millis = time.normalize(true); 427 428 int julianDay = Time.getJulianDay(millis, time.gmtoff); 429 time.setJulianDay(julianDay); 430 431 assertTrue(time.hour == 0 || time.hour == 1); 432 assertEquals(0, time.minute); 433 assertEquals(0, time.second); 434 435 millis = time.toMillis(false); 436 int day = Time.getJulianDay(millis, time.gmtoff); 437 438 assertEquals(day, julianDay); 439 } 440 } 441