VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/timelocal-posix.cpp@ 78253

Last change on this file since 78253 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 7.2 KB
Line 
1/* $Id $ */
2/** @file
3 * IPRT - Local Time, Posix.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_TIME
32#define RTTIME_INCL_TIMEVAL
33#include <iprt/types.h>
34#include <iprt/assert.h>
35
36#include <sys/time.h>
37#include <time.h>
38
39#include <iprt/time.h>
40
41
42/**
43 * This tries to find the UTC offset for a given timespec.
44 *
45 * It does probably not take into account changes in daylight
46 * saving over the years or similar stuff.
47 *
48 * @returns UTC offset in nanoseconds.
49 * @param pTime The time.
50 * @param fCurrentTime Whether the input is current time or not.
51 * This is for avoid infinit recursion on errors in the fallback path.
52 */
53static int64_t rtTimeLocalUTCOffset(PCRTTIMESPEC pTime, bool fCurrentTime)
54{
55 RTTIMESPEC Fallback;
56
57 /*
58 * Convert to time_t.
59 */
60 int64_t i64UnixTime = RTTimeSpecGetSeconds(pTime);
61 time_t UnixTime = i64UnixTime;
62 if (UnixTime != i64UnixTime)
63 return fCurrentTime ? 0 : rtTimeLocalUTCOffset(RTTimeNow(&Fallback), true);
64
65 /*
66 * Explode it as both local and UTC time.
67 */
68 struct tm TmLocal;
69 if ( !localtime_r(&UnixTime, &TmLocal)
70 || !TmLocal.tm_year)
71 return fCurrentTime ? 0 : rtTimeLocalUTCOffset(RTTimeNow(&Fallback), true);
72 struct tm TmUtc;
73 if (!gmtime_r(&UnixTime, &TmUtc))
74 return fCurrentTime ? 0 : rtTimeLocalUTCOffset(RTTimeNow(&Fallback), true);
75
76 /*
77 * Calc the difference (if any).
78 * We ASSUME that the difference is less that 24 hours.
79 */
80 if ( TmLocal.tm_hour == TmUtc.tm_hour
81 && TmLocal.tm_min == TmUtc.tm_min
82 && TmLocal.tm_sec == TmUtc.tm_sec
83 && TmLocal.tm_mday == TmUtc.tm_mday)
84 return 0;
85
86 int cLocalSecs = TmLocal.tm_hour * 3600
87 + TmLocal.tm_min * 60
88 + TmLocal.tm_sec;
89 int cUtcSecs = TmUtc.tm_hour * 3600
90 + TmUtc.tm_min * 60
91 + TmUtc.tm_sec;
92 if (TmLocal.tm_mday != TmUtc.tm_mday)
93 {
94 /*
95 * Must add 24 hours to the value that is ahead of the other.
96 *
97 * To determine which is ahead was busted for a long long time (bugref:9078),
98 * so here are some examples and two different approaches.
99 *
100 * TmLocal TmUtc => Add 24:00 to => Diff
101 * 2007-04-02 01:00 2007-04-01 23:00 => TmLocal => +02:00
102 * 2007-04-01 01:00 2007-03-31 23:00 => TmLocal => +02:00
103 * 2007-03-31 01:00 2007-03-30 23:00 => TmLocal => +02:00
104 *
105 * 2007-04-01 01:00 2007-04-02 23:00 => TmUtc => -02:00
106 * 2007-03-31 23:00 2007-04-01 01:00 => TmUtc => -02:00
107 * 2007-03-30 23:00 2007-03-31 01:00 => TmUtc => -02:00
108 *
109 */
110#if 0
111 /* Using day of month turned out to be a little complicated. */
112 if ( ( TmLocal.tm_mday > TmUtc.tm_mday
113 && (TmUtc.tm_mday != 1 || TmLocal.tm_mday < 28) )
114 || (TmLocal.tm_mday == 1 && TmUtc.tm_mday >= 28) )
115 {
116 cLocalSecs += 24*60*60;
117 Assert( TmLocal.tm_yday - TmUtc.tm_yday == 1
118 || (TmLocal.tm_yday == 0 && TmUtc.tm_yday >= 364 && TmLocal.tm_year == TmUtc.tm_year + 1));
119 }
120 else
121 {
122 cUtcSecs += 24*60*60;
123 Assert( TmUtc.tm_yday - TmLocal.tm_yday == 1
124 || (TmUtc.tm_yday == 0 && TmLocal.tm_yday >= 364 && TmUtc.tm_year == TmLocal.tm_year + 1));
125 }
126#else
127 /* Using day of year and year is simpler. */
128 if ( ( TmLocal.tm_year == TmUtc.tm_year
129 && TmLocal.tm_yday > TmUtc.tm_yday)
130 || TmLocal.tm_year > TmUtc.tm_year)
131 {
132 cLocalSecs += 24*60*60;
133 Assert( TmLocal.tm_yday - TmUtc.tm_yday == 1
134 || (TmLocal.tm_yday == 0 && TmUtc.tm_yday >= 364 && TmLocal.tm_year == TmUtc.tm_year + 1));
135 }
136 else
137 {
138 cUtcSecs += 24*60*60;
139 Assert( TmUtc.tm_yday - TmLocal.tm_yday == 1
140 || (TmUtc.tm_yday == 0 && TmLocal.tm_yday >= 364 && TmUtc.tm_year == TmLocal.tm_year + 1));
141 }
142#endif
143 }
144
145 return (cLocalSecs - cUtcSecs) * INT64_C(1000000000);
146}
147
148
149/**
150 * Gets the current delta between UTC and local time.
151 *
152 * @code
153 * RTTIMESPEC LocalTime;
154 * RTTimeSpecAddNano(RTTimeNow(&LocalTime), RTTimeLocalDeltaNano());
155 * @endcode
156 *
157 * @returns Returns the nanosecond delta between UTC and local time.
158 */
159RTDECL(int64_t) RTTimeLocalDeltaNano(void)
160{
161 RTTIMESPEC Time;
162 return rtTimeLocalUTCOffset(RTTimeNow(&Time), true /* current time, skip fallback */);
163}
164
165
166/**
167 * Gets the delta between UTC and local time at the given time.
168 *
169 * @code
170 * RTTIMESPEC LocalTime;
171 * RTTimeNow(&LocalTime);
172 * RTTimeSpecAddNano(&LocalTime, RTTimeLocalDeltaNanoFor(&LocalTime));
173 * @endcode
174 *
175 * @param pTimeSpec The time spec giving the time to get the delta for.
176 * @returns Returns the nanosecond delta between UTC and local time.
177 */
178RTDECL(int64_t) RTTimeLocalDeltaNanoFor(PCRTTIMESPEC pTimeSpec)
179{
180 AssertPtr(pTimeSpec);
181 return rtTimeLocalUTCOffset(pTimeSpec, false /* current time, skip fallback */);
182}
183
184
185/**
186 * Explodes a time spec to the localized timezone.
187 *
188 * @returns pTime.
189 * @param pTime Where to store the exploded time.
190 * @param pTimeSpec The time spec to exploded. (UTC)
191 */
192RTDECL(PRTTIME) RTTimeLocalExplode(PRTTIME pTime, PCRTTIMESPEC pTimeSpec)
193{
194 RTTIMESPEC LocalTime = *pTimeSpec;
195 int64_t cNsUtcOffset = rtTimeLocalUTCOffset(&LocalTime, true /* current time, skip fallback */);
196 RTTimeSpecAddNano(&LocalTime, cNsUtcOffset);
197 pTime = RTTimeExplode(pTime, &LocalTime);
198 if (pTime)
199 {
200 pTime->fFlags = (pTime->fFlags & ~RTTIME_FLAGS_TYPE_MASK) | RTTIME_FLAGS_TYPE_LOCAL;
201 pTime->offUTC = cNsUtcOffset / RT_NS_1MIN;
202 }
203 return pTime;
204}
205
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette