VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use