• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <time.h>
6 
7 #include "base/threading/platform_thread.h"
8 #include "base/time.h"
9 #include "build/build_config.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 
12 using base::Time;
13 using base::TimeDelta;
14 using base::TimeTicks;
15 
16 // Test conversions to/from time_t and exploding/unexploding.
TEST(Time,TimeT)17 TEST(Time, TimeT) {
18   // C library time and exploded time.
19   time_t now_t_1 = time(NULL);
20   struct tm tms;
21 #if defined(OS_WIN)
22   localtime_s(&tms, &now_t_1);
23 #elif defined(OS_POSIX)
24   localtime_r(&now_t_1, &tms);
25 #endif
26 
27   // Convert to ours.
28   Time our_time_1 = Time::FromTimeT(now_t_1);
29   Time::Exploded exploded;
30   our_time_1.LocalExplode(&exploded);
31 
32   // This will test both our exploding and our time_t -> Time conversion.
33   EXPECT_EQ(tms.tm_year + 1900, exploded.year);
34   EXPECT_EQ(tms.tm_mon + 1, exploded.month);
35   EXPECT_EQ(tms.tm_mday, exploded.day_of_month);
36   EXPECT_EQ(tms.tm_hour, exploded.hour);
37   EXPECT_EQ(tms.tm_min, exploded.minute);
38   EXPECT_EQ(tms.tm_sec, exploded.second);
39 
40   // Convert exploded back to the time struct.
41   Time our_time_2 = Time::FromLocalExploded(exploded);
42   EXPECT_TRUE(our_time_1 == our_time_2);
43 
44   time_t now_t_2 = our_time_2.ToTimeT();
45   EXPECT_EQ(now_t_1, now_t_2);
46 
47   EXPECT_EQ(10, Time().FromTimeT(10).ToTimeT());
48   EXPECT_EQ(10.0, Time().FromTimeT(10).ToDoubleT());
49 
50   // Conversions of 0 should stay 0.
51   EXPECT_EQ(0, Time().ToTimeT());
52   EXPECT_EQ(0, Time::FromTimeT(0).ToInternalValue());
53 }
54 
TEST(Time,FromExplodedWithMilliseconds)55 TEST(Time, FromExplodedWithMilliseconds) {
56   // Some platform implementations of FromExploded are liable to drop
57   // milliseconds if we aren't careful.
58   Time now = Time::NowFromSystemTime();
59   Time::Exploded exploded1 = {0};
60   now.UTCExplode(&exploded1);
61   exploded1.millisecond = 500;
62   Time time = Time::FromUTCExploded(exploded1);
63   Time::Exploded exploded2 = {0};
64   time.UTCExplode(&exploded2);
65   EXPECT_EQ(exploded1.millisecond, exploded2.millisecond);
66 }
67 
TEST(Time,ZeroIsSymmetric)68 TEST(Time, ZeroIsSymmetric) {
69   Time zero_time(Time::FromTimeT(0));
70   EXPECT_EQ(0, zero_time.ToTimeT());
71 
72   EXPECT_EQ(0.0, zero_time.ToDoubleT());
73 }
74 
TEST(Time,LocalExplode)75 TEST(Time, LocalExplode) {
76   Time a = Time::Now();
77   Time::Exploded exploded;
78   a.LocalExplode(&exploded);
79 
80   Time b = Time::FromLocalExploded(exploded);
81 
82   // The exploded structure doesn't have microseconds, and on Mac & Linux, the
83   // internal OS conversion uses seconds, which will cause truncation. So we
84   // can only make sure that the delta is within one second.
85   EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1));
86 }
87 
TEST(Time,UTCExplode)88 TEST(Time, UTCExplode) {
89   Time a = Time::Now();
90   Time::Exploded exploded;
91   a.UTCExplode(&exploded);
92 
93   Time b = Time::FromUTCExploded(exploded);
94   EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1));
95 }
96 
TEST(Time,LocalMidnight)97 TEST(Time, LocalMidnight) {
98   Time::Exploded exploded;
99   Time::Now().LocalMidnight().LocalExplode(&exploded);
100   EXPECT_EQ(0, exploded.hour);
101   EXPECT_EQ(0, exploded.minute);
102   EXPECT_EQ(0, exploded.second);
103   EXPECT_EQ(0, exploded.millisecond);
104 }
105 
TEST(TimeTicks,Deltas)106 TEST(TimeTicks, Deltas) {
107   for (int index = 0; index < 50; index++) {
108     TimeTicks ticks_start = TimeTicks::Now();
109     base::PlatformThread::Sleep(10);
110     TimeTicks ticks_stop = TimeTicks::Now();
111     TimeDelta delta = ticks_stop - ticks_start;
112     // Note:  Although we asked for a 10ms sleep, if the
113     // time clock has a finer granularity than the Sleep()
114     // clock, it is quite possible to wakeup early.  Here
115     // is how that works:
116     //      Time(ms timer)      Time(us timer)
117     //          5                   5010
118     //          6                   6010
119     //          7                   7010
120     //          8                   8010
121     //          9                   9000
122     // Elapsed  4ms                 3990us
123     //
124     // Unfortunately, our InMilliseconds() function truncates
125     // rather than rounds.  We should consider fixing this
126     // so that our averages come out better.
127     EXPECT_GE(delta.InMilliseconds(), 9);
128     EXPECT_GE(delta.InMicroseconds(), 9000);
129     EXPECT_EQ(delta.InSeconds(), 0);
130   }
131 }
132 
TEST(TimeTicks,HighResNow)133 TEST(TimeTicks, HighResNow) {
134 #if defined(OS_WIN)
135   // HighResNow doesn't work on some systems.  Since the product still works
136   // even if it doesn't work, it makes this entire test questionable.
137   if (!TimeTicks::IsHighResClockWorking())
138     return;
139 #endif
140 
141   // Why do we loop here?
142   // We're trying to measure that intervals increment in a VERY small amount
143   // of time --  less than 15ms.  Unfortunately, if we happen to have a
144   // context switch in the middle of our test, the context switch could easily
145   // exceed our limit.  So, we iterate on this several times.  As long as we're
146   // able to detect the fine-granularity timers at least once, then the test
147   // has succeeded.
148 
149   const int kTargetGranularityUs = 15000;  // 15ms
150 
151   bool success = false;
152   int retries = 100;  // Arbitrary.
153   TimeDelta delta;
154   while (!success && retries--) {
155     TimeTicks ticks_start = TimeTicks::HighResNow();
156     // Loop until we can detect that the clock has changed.  Non-HighRes timers
157     // will increment in chunks, e.g. 15ms.  By spinning until we see a clock
158     // change, we detect the minimum time between measurements.
159     do {
160       delta = TimeTicks::HighResNow() - ticks_start;
161     } while (delta.InMilliseconds() == 0);
162 
163     if (delta.InMicroseconds() <= kTargetGranularityUs)
164       success = true;
165   }
166 
167   // In high resolution mode, we expect to see the clock increment
168   // in intervals less than 15ms.
169   EXPECT_TRUE(success);
170 }
171 
TEST(TimeDelta,FromAndIn)172 TEST(TimeDelta, FromAndIn) {
173   EXPECT_TRUE(TimeDelta::FromDays(2) == TimeDelta::FromHours(48));
174   EXPECT_TRUE(TimeDelta::FromHours(3) == TimeDelta::FromMinutes(180));
175   EXPECT_TRUE(TimeDelta::FromMinutes(2) == TimeDelta::FromSeconds(120));
176   EXPECT_TRUE(TimeDelta::FromSeconds(2) == TimeDelta::FromMilliseconds(2000));
177   EXPECT_TRUE(TimeDelta::FromMilliseconds(2) ==
178               TimeDelta::FromMicroseconds(2000));
179   EXPECT_EQ(13, TimeDelta::FromDays(13).InDays());
180   EXPECT_EQ(13, TimeDelta::FromHours(13).InHours());
181   EXPECT_EQ(13, TimeDelta::FromMinutes(13).InMinutes());
182   EXPECT_EQ(13, TimeDelta::FromSeconds(13).InSeconds());
183   EXPECT_EQ(13.0, TimeDelta::FromSeconds(13).InSecondsF());
184   EXPECT_EQ(13, TimeDelta::FromMilliseconds(13).InMilliseconds());
185   EXPECT_EQ(13.0, TimeDelta::FromMilliseconds(13).InMillisecondsF());
186   EXPECT_EQ(13, TimeDelta::FromMicroseconds(13).InMicroseconds());
187 }
188 
189 #if defined(OS_POSIX)
TEST(TimeDelta,TimeSpecConversion)190 TEST(TimeDelta, TimeSpecConversion) {
191   struct timespec result = TimeDelta::FromSeconds(0).ToTimeSpec();
192   EXPECT_EQ(result.tv_sec, 0);
193   EXPECT_EQ(result.tv_nsec, 0);
194 
195   result = TimeDelta::FromSeconds(1).ToTimeSpec();
196   EXPECT_EQ(result.tv_sec, 1);
197   EXPECT_EQ(result.tv_nsec, 0);
198 
199   result = TimeDelta::FromMicroseconds(1).ToTimeSpec();
200   EXPECT_EQ(result.tv_sec, 0);
201   EXPECT_EQ(result.tv_nsec, 1000);
202 
203   result = TimeDelta::FromMicroseconds(
204       Time::kMicrosecondsPerSecond + 1).ToTimeSpec();
205   EXPECT_EQ(result.tv_sec, 1);
206   EXPECT_EQ(result.tv_nsec, 1000);
207 }
208 #endif  // OS_POSIX
209 
210 // Our internal time format is serialized in things like databases, so it's
211 // important that it's consistent across all our platforms.  We use the 1601
212 // Windows epoch as the internal format across all platforms.
TEST(TimeDelta,WindowsEpoch)213 TEST(TimeDelta, WindowsEpoch) {
214   Time::Exploded exploded;
215   exploded.year = 1970;
216   exploded.month = 1;
217   exploded.day_of_week = 0;  // Should be unusued.
218   exploded.day_of_month = 1;
219   exploded.hour = 0;
220   exploded.minute = 0;
221   exploded.second = 0;
222   exploded.millisecond = 0;
223   Time t = Time::FromUTCExploded(exploded);
224   // Unix 1970 epoch.
225   EXPECT_EQ(GG_INT64_C(11644473600000000), t.ToInternalValue());
226 
227   // We can't test 1601 epoch, since the system time functions on Linux
228   // only compute years starting from 1900.
229 }
230