]>
git.proxmox.com Git - mirror_edk2.git/blob - StdLib/LibC/Time/Time.c
2 Definitions and Implementation for <time.h>.
4 Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available under
6 the terms and conditions of the BSD License that accompanies this distribution.
7 The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 Portions derived from the NIH time zone package file, localtime.c,
14 which contains the following notice:
16 This file is in the public domain, so clarified as of
17 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov).
19 NetBSD: localtime.c,v 1.39 2006/03/22 14:01:30 christos Exp
22 #include <Library/UefiLib.h>
23 #include <Library/TimerLib.h>
24 #include <Library/BaseLib.h>
25 #include <Library/UefiRuntimeServicesTableLib.h>
26 //#include <Library/UefiRuntimeLib.h>
28 #include <LibConfig.h>
33 #include <reentrant.h>
37 #include <extern.h> // Library/include/extern.h: Private to implementation
39 #if defined(_MSC_VER) /* Handle Microsoft VC++ compiler specifics. */
40 // Keep compiler quiet about casting from function to data pointers
41 #pragma warning ( disable : 4054 )
42 #endif /* defined(_MSC_VER) */
44 /* ####################### Private Data ################################# */
47 static EFI_TIME TimeBuffer
;
49 static UINT16 MonthOffs
[12] = {
55 static clock_t y2kOffs
= 730485;
58 const int mon_lengths
[2][MONSPERYEAR
] = {
59 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
60 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
63 const int year_lengths
[2] = {
64 DAYSPERNYEAR
, DAYSPERLYEAR
68 static const char *wday_name
[7] = {
69 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
72 static const char *mon_name
[12] = {
73 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
74 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
77 static int gmt_is_set
;
79 /* ############### Implementation Functions ############################ */
82 localsub(const time_t * const timep
, const long offset
, struct tm
* const tmp
);
87 return gMD
->ClocksPerSecond
;
92 const time_t * const timep
,
94 const struct state
* const sp
,
98 const struct lsinfo
* lp
;
104 time_t /*INTN*/ corr
;
111 i
= (sp
== NULL
) ? 0 : sp
->leapcnt
;
112 #endif /* defined ALL_STATE */
115 #endif /* State Farm */
118 if (*timep
>= lp
->ls_trans
) {
119 if (*timep
== lp
->ls_trans
) {
120 hit
= ((i
== 0 && lp
->ls_corr
> 0) ||
121 lp
->ls_corr
> sp
->lsis
[i
- 1].ls_corr
);
124 sp
->lsis
[i
].ls_trans
== sp
->lsis
[i
- 1].ls_trans
+ 1 &&
125 sp
->lsis
[i
].ls_corr
== sp
->lsis
[i
- 1].ls_corr
+ 1 )
135 days
= *timep
/ SECSPERDAY
;
136 rem
= *timep
% SECSPERDAY
;
137 rem
+= (offset
- corr
);
142 while (rem
>= SECSPERDAY
) {
146 tmp
->tm_hour
= (int) (rem
/ SECSPERHOUR
);
147 rem
= rem
% SECSPERHOUR
;
148 tmp
->tm_min
= (int) (rem
/ SECSPERMIN
);
150 ** A positive leap second requires a special
151 ** representation. This uses "... ??:59:60" et seq.
153 tmp
->tm_sec
= (int) (rem
% SECSPERMIN
) + hit
;
154 tmp
->tm_wday
= (int) ((EPOCH_WDAY
+ days
) % DAYSPERWEEK
);
155 if (tmp
->tm_wday
< 0)
156 tmp
->tm_wday
+= DAYSPERWEEK
;
158 while (days
< 0 || days
>= (LONG32
) year_lengths
[yleap
= isleap(y
)]) {
159 time_t /*INTN*/ newy
;
161 newy
= (y
+ days
/ DAYSPERNYEAR
);
164 days
-= (newy
- y
) * DAYSPERNYEAR
+
165 LEAPS_THRU_END_OF(newy
- 1) -
166 LEAPS_THRU_END_OF(y
- 1);
169 tmp
->tm_year
= (int)(y
- TM_YEAR_BASE
);
170 tmp
->tm_yday
= (int) days
;
171 ip
= mon_lengths
[yleap
];
172 for (tmp
->tm_mon
= 0; days
>= (LONG32
) ip
[tmp
->tm_mon
]; ++(tmp
->tm_mon
))
173 days
= days
- (LONG32
) ip
[tmp
->tm_mon
];
174 tmp
->tm_mday
= (int) (days
+ 1);
177 tmp
->TM_GMTOFF
= offset
;
178 #endif /* defined TM_GMTOFF */
181 /* ############### Time Manipulation Functions ########################## */
183 /** The clock function determines the processor time used.
185 @return The clock function returns the implementation's best
186 approximation to the processor time used by the program since the
187 beginning of an implementation-defined era related only to the
188 program invocation. To determine the time in seconds, the value
189 returned by the clock function should be divided by the value of
190 the macro CLOCKS_PER_SEC. If the processor time used is not
191 available or its value cannot be represented, the function
192 returns the value (clock_t)(-1).
194 On IA32 or X64 platforms, the value returned is the number of
195 CPU TimeStamp Counter ticks since the appliation started.
203 temp
= (clock_t)GetPerformanceCounter();
205 return temp
- gMD
->AppStartTime
;
214 difftime(time_t time1
, time_t time0
)
216 return (double)(time1
- time0
);
220 ** Adapted from code provided by Robert Elz, who writes:
221 ** The "best" way to do mktime I think is based on an idea of Bob
222 ** Kridle's (so its said...) from a long time ago.
223 ** [kridle@xinet.com as of 1996-01-16.]
224 ** It does a binary search of the time_t space. Since time_t's are
225 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
226 ** would still be very reasonable).
231 #endif /* !defined WRONG */
234 ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
238 increment_overflow(int * number
, int delta
)
244 return (*number
< number0
) != (delta
< 0);
248 normalize_overflow(int * const tensptr
, int * const unitsptr
, const int base
)
250 register int tensdelta
;
252 tensdelta
= (*unitsptr
>= 0) ?
253 (*unitsptr
/ base
) : (-1 - (-1 - *unitsptr
) / base
);
254 *unitsptr
-= tensdelta
* base
;
255 return increment_overflow(tensptr
, tensdelta
);
259 tmcomp(const struct tm
* const atmp
, const struct tm
* const btmp
)
263 if ((result
= (atmp
->tm_year
- btmp
->tm_year
)) == 0 &&
264 (result
= (atmp
->tm_mon
- btmp
->tm_mon
)) == 0 &&
265 (result
= (atmp
->tm_mday
- btmp
->tm_mday
)) == 0 &&
266 (result
= (atmp
->tm_hour
- btmp
->tm_hour
)) == 0 &&
267 (result
= (atmp
->tm_min
- btmp
->tm_min
)) == 0)
268 result
= atmp
->tm_sec
- btmp
->tm_sec
;
274 struct tm
* const tmp
,
275 void (* const funcp
)(const time_t*, long, struct tm
*),
278 const int do_norm_secs
281 register const struct state
* sp
;
285 register int saved_seconds
;
288 struct tm yourtm
, mytm
;
291 yourtm
= *tmp
; // Create a copy of tmp
293 if (normalize_overflow(&yourtm
.tm_min
, &yourtm
.tm_sec
,
297 if (normalize_overflow(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
))
299 if (normalize_overflow(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
))
301 if (normalize_overflow(&yourtm
.tm_year
, &yourtm
.tm_mon
, MONSPERYEAR
))
304 ** Turn yourtm.tm_year into an actual year number for now.
305 ** It is converted back to an offset from TM_YEAR_BASE later.
307 if (increment_overflow(&yourtm
.tm_year
, TM_YEAR_BASE
))
309 while (yourtm
.tm_mday
<= 0) {
310 if (increment_overflow(&yourtm
.tm_year
, -1))
312 i
= yourtm
.tm_year
+ (1 < yourtm
.tm_mon
);
313 yourtm
.tm_mday
+= year_lengths
[isleap(i
)];
315 while (yourtm
.tm_mday
> DAYSPERLYEAR
) {
316 i
= yourtm
.tm_year
+ (1 < yourtm
.tm_mon
);
317 yourtm
.tm_mday
-= year_lengths
[isleap(i
)];
318 if (increment_overflow(&yourtm
.tm_year
, 1))
322 i
= mon_lengths
[isleap(yourtm
.tm_year
)][yourtm
.tm_mon
];
323 if (yourtm
.tm_mday
<= i
)
326 if (++yourtm
.tm_mon
>= MONSPERYEAR
) {
328 if (increment_overflow(&yourtm
.tm_year
, 1))
332 if (increment_overflow(&yourtm
.tm_year
, -TM_YEAR_BASE
))
334 if (yourtm
.tm_sec
>= 0 && yourtm
.tm_sec
< SECSPERMIN
)
336 else if (yourtm
.tm_year
+ TM_YEAR_BASE
< EPOCH_YEAR
) {
338 ** We can't set tm_sec to 0, because that might push the
339 ** time below the minimum representable time.
340 ** Set tm_sec to 59 instead.
341 ** This assumes that the minimum representable time is
342 ** not in the same minute that a leap second was deleted from,
343 ** which is a safer assumption than using 58 would be.
345 if (increment_overflow(&yourtm
.tm_sec
, 1 - SECSPERMIN
))
347 saved_seconds
= yourtm
.tm_sec
;
348 yourtm
.tm_sec
= SECSPERMIN
- 1;
350 saved_seconds
= yourtm
.tm_sec
;
354 ** Divide the search space in half
355 ** (this works whether time_t is signed or unsigned).
357 bits
= TYPE_BIT(time_t) - 1;
359 ** Set t to the midpoint of our binary search.
361 ** If time_t is signed, then 0 is just above the median,
362 ** assuming two's complement arithmetic.
363 ** If time_t is unsigned, then (1 << bits) is just above the median.
365 t
= TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits
);
367 (*funcp
)(&t
, offset
, &mytm
); // Convert t to broken-down time in mytm
368 dir
= tmcomp(&mytm
, &yourtm
); // Is mytm larger, equal, or less than yourtm?
369 if (dir
!= 0) { // If mytm != yourtm...
370 if (bits
-- < 0) // If we have exhausted all the bits..
371 return WRONG
; // Return that we failed
372 if (bits
< 0) // If on the last bit...
373 --t
; /* may be needed if new t is minimal */
374 else if (dir
> 0) // else if mytm > yourtm...
375 t
-= ((time_t) 1) << bits
; // subtract half the remaining time-space
376 else t
+= ((time_t) 1) << bits
; // otherwise add half the remaining time-space
377 continue; // Repeat for the next half
379 if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
382 ** Right time, wrong type.
383 ** Hunt for right time, right type.
384 ** It's okay to guess wrong since the guess
388 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
390 sp
= (const struct state
*)
391 (((void *) funcp
== (void *) localsub
) ?
396 #endif /* defined ALL_STATE */
397 for (i
= sp
->typecnt
- 1; i
>= 0; --i
) {
398 if (sp
->ttis
[i
].tt_isdst
!= yourtm
.tm_isdst
)
400 for (j
= sp
->typecnt
- 1; j
>= 0; --j
) {
401 if (sp
->ttis
[j
].tt_isdst
== yourtm
.tm_isdst
)
403 newt
= t
+ sp
->ttis
[j
].tt_gmtoff
-
404 sp
->ttis
[i
].tt_gmtoff
;
405 (*funcp
)(&newt
, offset
, &mytm
);
406 if (tmcomp(&mytm
, &yourtm
) != 0)
408 if (mytm
.tm_isdst
!= yourtm
.tm_isdst
)
420 newt
= t
+ saved_seconds
;
421 if ((newt
< t
) != (saved_seconds
< 0))
424 (*funcp
)(&t
, offset
, tmp
);
430 time2(struct tm
* const tmp
, void (* const funcp
)(const time_t*, long, struct tm
*),
431 const long offset
, int * const okayp
)
436 ** First try without normalization of seconds
437 ** (in case tm_sec contains a value associated with a leap second).
438 ** If that fails, try with normalization of seconds.
440 t
= time2sub(tmp
, funcp
, offset
, okayp
, FALSE
);
441 return *okayp
? t
: time2sub(tmp
, funcp
, offset
, okayp
, TRUE
);
446 struct tm
* const tmp
,
447 void (* const funcp
)(const time_t *, long, struct tm
*),
452 register const struct state
* sp
;
453 register int samei
, otheri
;
454 register int sameind
, otherind
;
457 int seen
[TZ_MAX_TYPES
];
458 int types
[TZ_MAX_TYPES
];
461 if (tmp
->tm_isdst
> 1)
463 t
= time2(tmp
, funcp
, offset
, &okay
);
466 ** PCTS code courtesy Grant Sullivan (grant@osf.org).
470 if (tmp
->tm_isdst
< 0)
471 tmp
->tm_isdst
= 0; /* reset to std and try again */
472 #endif /* defined PCTS */
474 if (okay
|| tmp
->tm_isdst
< 0)
476 #endif /* !defined PCTS */
478 ** We're supposed to assume that somebody took a time of one type
479 ** and did some math on it that yielded a "struct tm" that's bad.
480 ** We try to divine the type they started from and adjust to the
484 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
486 sp
= (const struct state
*) (((void *) funcp
== (void *) localsub
) ?
491 #endif /* defined ALL_STATE */
492 for (i
= 0; i
< sp
->typecnt
; ++i
)
495 for (i
= sp
->timecnt
- 1; i
>= 0; --i
)
496 if (!seen
[sp
->types
[i
]]) {
497 seen
[sp
->types
[i
]] = TRUE
;
498 types
[nseen
++] = sp
->types
[i
];
500 for (sameind
= 0; sameind
< nseen
; ++sameind
) {
501 samei
= types
[sameind
];
502 if (sp
->ttis
[samei
].tt_isdst
!= tmp
->tm_isdst
)
504 for (otherind
= 0; otherind
< nseen
; ++otherind
) {
505 otheri
= types
[otherind
];
506 if (sp
->ttis
[otheri
].tt_isdst
== tmp
->tm_isdst
)
508 tmp
->tm_sec
+= (int)(sp
->ttis
[otheri
].tt_gmtoff
-
509 sp
->ttis
[samei
].tt_gmtoff
);
510 tmp
->tm_isdst
= !tmp
->tm_isdst
;
511 t
= time2(tmp
, funcp
, offset
, &okay
);
514 tmp
->tm_sec
-= (int)(sp
->ttis
[otheri
].tt_gmtoff
-
515 sp
->ttis
[samei
].tt_gmtoff
);
516 tmp
->tm_isdst
= !tmp
->tm_isdst
;
522 /** The mktime function converts the broken-down time, expressed as local time,
523 in the structure pointed to by timeptr into a calendar time value with the
524 same encoding as that of the values returned by the time function. The
525 original values of the tm_wday and tm_yday components of the structure are
526 ignored, and the original values of the other components are not restricted
527 to the ranges indicated above. Thus, a positive or zero value for tm_isdst
528 causes the mktime function to presume initially that Daylight Saving Time,
529 respectively, is or is not in effect for the specified time. A negative
530 value causes it to attempt to determine whether Daylight Saving Time is in
531 effect for the specified time. On successful completion, the values of the
532 tm_wday and tm_yday components of the structure are set appropriately, and
533 the other components are set to represent the specified calendar time, but
534 with their values forced to the ranges indicated above; the final value of
535 tm_mday is not set until tm_mon and tm_year are determined.
537 @return The mktime function returns the specified calendar time encoded
538 as a value of type time_t. If the calendar time cannot be
539 represented, the function returns the value (time_t)(-1).
542 mktime(struct tm
*timeptr
)
547 rwlock_wrlock(&lcl_lock
);
549 result
= time1(timeptr
, &localsub
, 0L);
550 rwlock_unlock(&lcl_lock
);
554 /** The time function determines the current calendar time. The encoding of
555 the value is unspecified.
557 @return The time function returns the implementation's best approximation
558 to the current calendar time. The value (time_t)(-1) is returned
559 if the calendar time is not available. If timer is not a null
560 pointer, the return value is also assigned to the object it
571 ET
= &gMD
->TimeBuffer
;
575 Status
= gRT
->GetTime( ET
, NULL
);
576 // Status = EfiGetTime( ET, NULL);
578 if( Status
!= RETURN_SUCCESS
) {
582 // Convert EFI time to broken-down time.
586 CalTime
= mktime(&gMD
->BDTime
);
591 return CalTime
; // Return calendar time in microseconds
594 /* ################# Time Conversion Functions ########################## */
596 Except for the strftime function, these functions each return a pointer to
597 one of two types of static objects: a broken-down time structure or an
598 array of char. Execution of any of the functions that return a pointer to
599 one of these object types may overwrite the information in any object of
600 the same type pointed to by the value returned from any previous call to
601 any of them. The implementation shall behave as if no other library
602 functions call these functions.
605 /** The asctime function converts the broken-down time in the structure pointed
606 to by timeptr into a string in the form
607 Sun Sep 16 01:03:52 1973\n\0
608 using the equivalent of the following algorithm.
610 char *asctime(const struct tm *timeptr)
612 static const char wday_name[7][3] = {
613 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
615 static const char mon_name[12][3] = {
616 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
617 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
619 static char result[26];
620 sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
621 wday_name[timeptr->tm_wday],
622 mon_name[timeptr->tm_mon],
623 timeptr->tm_mday, timeptr->tm_hour,
624 timeptr->tm_min, timeptr->tm_sec,
625 1900 + timeptr->tm_year);
628 @return The asctime function returns a pointer to the string.
631 asctime(const struct tm
*timeptr
)
633 register const char * wn
;
634 register const char * mn
;
636 if (timeptr
->tm_wday
< 0 || timeptr
->tm_wday
>= DAYSPERWEEK
)
638 else wn
= wday_name
[timeptr
->tm_wday
];
639 if (timeptr
->tm_mon
< 0 || timeptr
->tm_mon
>= MONSPERYEAR
)
641 else mn
= mon_name
[timeptr
->tm_mon
];
643 ** The X3J11-suggested format is
644 ** "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"
645 ** Since the .2 in 02.2d is ignored, we drop it.
647 (void)snprintf(gMD
->ASasctime
,
648 sizeof (char[ASCTIME_BUFLEN
]),
649 "%.3s %.3s%3d %02d:%02d:%02d %d\r\n", // explicit CRLF for EFI
651 timeptr
->tm_mday
, timeptr
->tm_hour
,
652 timeptr
->tm_min
, timeptr
->tm_sec
,
653 TM_YEAR_BASE
+ timeptr
->tm_year
);
654 return gMD
->ASasctime
;
660 ctime(const time_t *timer
)
662 return asctime(localtime(timer
));
666 ** gmtsub is to gmtime as localsub is to localtime.
670 const time_t * const timep
,
672 struct tm
* const tmp
676 static mutex_t gmt_mutex
= MUTEX_INITIALIZER
;
679 mutex_lock(&gmt_mutex
);
683 gmtptr
= (struct state
*) malloc(sizeof *gmtptr
);
685 #endif /* defined ALL_STATE */
688 mutex_unlock(&gmt_mutex
);
689 timesub(timep
, offset
, gmtptr
, tmp
);
692 ** Could get fancy here and deliver something such as
693 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
694 ** but this is no time for a treasure hunt.
697 tmp
->TM_ZONE
= (__aconst
char *)__UNCONST(wildabbr
);
701 tmp
->TM_ZONE
= (__aconst
char *)__UNCONST(gmt
);
702 else tmp
->TM_ZONE
= gmtptr
->chars
;
703 #endif /* defined ALL_STATE */
705 tmp
->TM_ZONE
= gmtptr
->chars
;
706 #endif /* State Farm */
708 #endif /* defined TM_ZONE */
714 gmtime(const time_t *timer
)
716 gmtsub(timer
, 0L, &gMD
->BDTime
);
721 localsub(const time_t * const timep
, const long offset
, struct tm
* const tmp
)
723 register struct state
* sp
;
724 register const struct ttinfo
* ttisp
;
726 const time_t t
= *timep
;
731 gmtsub(timep
, offset
, tmp
);
734 #endif /* defined ALL_STATE */
735 if (sp
->timecnt
== 0 || t
< sp
->ats
[0]) {
737 while (sp
->ttis
[i
].tt_isdst
)
738 if (++i
>= sp
->typecnt
) {
743 for (i
= 1; i
< sp
->timecnt
; ++i
)
746 i
= sp
->types
[i
- 1];
748 ttisp
= &sp
->ttis
[i
];
750 ** To get (wrong) behavior that's compatible with System V Release 2.0
751 ** you'd replace the statement below with
752 ** t += ttisp->tt_gmtoff;
753 ** timesub(&t, 0L, sp, tmp);
755 timesub(&t
, ttisp
->tt_gmtoff
, sp
, tmp
);
756 tmp
->tm_isdst
= ttisp
->tt_isdst
;
757 tzname
[tmp
->tm_isdst
] = &sp
->chars
[ttisp
->tt_abbrind
];
759 tmp
->TM_ZONE
= &sp
->chars
[ttisp
->tt_abbrind
];
760 #endif /* defined TM_ZONE */
766 localtime(const time_t *timer
)
769 localsub(timer
, 0L, &gMD
->BDTime
);