time_unittest.cc revision 4a5e2dc747d50c653511c68ccb2cfbfb740bd5a7
1// Copyright (c) 2006-2008 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/platform_thread.h"
8#include "base/time.h"
9#include "build/build_config.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12using base::Time;
13using base::TimeDelta;
14using base::TimeTicks;
15
16// Test conversions to/from time_t and exploding/unexploding.
17TEST(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
55TEST(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
68TEST(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
75TEST(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
88TEST(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
97TEST(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
106TEST(TimeTicks, Deltas) {
107  for (int index = 0; index < 50; index++) {
108    TimeTicks ticks_start = TimeTicks::Now();
109    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
133TEST(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
172TEST(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)
190TEST(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.
213TEST(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