]>
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 ########################## */
186 difftime(time_t time1
, time_t time0
)
188 return (double)(time1
- time0
);
192 ** Adapted from code provided by Robert Elz, who writes:
193 ** The "best" way to do mktime I think is based on an idea of Bob
194 ** Kridle's (so its said...) from a long time ago.
195 ** [kridle@xinet.com as of 1996-01-16.]
196 ** It does a binary search of the time_t space. Since time_t's are
197 ** just 32 bits, its a max of 32 iterations (even at 64 bits it
198 ** would still be very reasonable).
203 #endif /* !defined WRONG */
206 ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
210 increment_overflow(int * number
, int delta
)
216 return (*number
< number0
) != (delta
< 0);
220 normalize_overflow(int * const tensptr
, int * const unitsptr
, const int base
)
222 register int tensdelta
;
224 tensdelta
= (*unitsptr
>= 0) ?
225 (*unitsptr
/ base
) : (-1 - (-1 - *unitsptr
) / base
);
226 *unitsptr
-= tensdelta
* base
;
227 return increment_overflow(tensptr
, tensdelta
);
231 tmcomp(const struct tm
* const atmp
, const struct tm
* const btmp
)
235 if ((result
= (atmp
->tm_year
- btmp
->tm_year
)) == 0 &&
236 (result
= (atmp
->tm_mon
- btmp
->tm_mon
)) == 0 &&
237 (result
= (atmp
->tm_mday
- btmp
->tm_mday
)) == 0 &&
238 (result
= (atmp
->tm_hour
- btmp
->tm_hour
)) == 0 &&
239 (result
= (atmp
->tm_min
- btmp
->tm_min
)) == 0)
240 result
= atmp
->tm_sec
- btmp
->tm_sec
;
246 struct tm
* const tmp
,
247 void (* const funcp
)(const time_t*, long, struct tm
*),
250 const int do_norm_secs
253 register const struct state
* sp
;
257 register int saved_seconds
;
260 struct tm yourtm
, mytm
;
263 yourtm
= *tmp
; // Create a copy of tmp
265 if (normalize_overflow(&yourtm
.tm_min
, &yourtm
.tm_sec
,
269 if (normalize_overflow(&yourtm
.tm_hour
, &yourtm
.tm_min
, MINSPERHOUR
))
271 if (normalize_overflow(&yourtm
.tm_mday
, &yourtm
.tm_hour
, HOURSPERDAY
))
273 if (normalize_overflow(&yourtm
.tm_year
, &yourtm
.tm_mon
, MONSPERYEAR
))
276 ** Turn yourtm.tm_year into an actual year number for now.
277 ** It is converted back to an offset from TM_YEAR_BASE later.
279 if (increment_overflow(&yourtm
.tm_year
, TM_YEAR_BASE
))
281 while (yourtm
.tm_mday
<= 0) {
282 if (increment_overflow(&yourtm
.tm_year
, -1))
284 i
= yourtm
.tm_year
+ (1 < yourtm
.tm_mon
);
285 yourtm
.tm_mday
+= year_lengths
[isleap(i
)];
287 while (yourtm
.tm_mday
> DAYSPERLYEAR
) {
288 i
= yourtm
.tm_year
+ (1 < yourtm
.tm_mon
);
289 yourtm
.tm_mday
-= year_lengths
[isleap(i
)];
290 if (increment_overflow(&yourtm
.tm_year
, 1))
294 i
= mon_lengths
[isleap(yourtm
.tm_year
)][yourtm
.tm_mon
];
295 if (yourtm
.tm_mday
<= i
)
298 if (++yourtm
.tm_mon
>= MONSPERYEAR
) {
300 if (increment_overflow(&yourtm
.tm_year
, 1))
304 if (increment_overflow(&yourtm
.tm_year
, -TM_YEAR_BASE
))
306 if (yourtm
.tm_sec
>= 0 && yourtm
.tm_sec
< SECSPERMIN
)
308 else if (yourtm
.tm_year
+ TM_YEAR_BASE
< EPOCH_YEAR
) {
310 ** We can't set tm_sec to 0, because that might push the
311 ** time below the minimum representable time.
312 ** Set tm_sec to 59 instead.
313 ** This assumes that the minimum representable time is
314 ** not in the same minute that a leap second was deleted from,
315 ** which is a safer assumption than using 58 would be.
317 if (increment_overflow(&yourtm
.tm_sec
, 1 - SECSPERMIN
))
319 saved_seconds
= yourtm
.tm_sec
;
320 yourtm
.tm_sec
= SECSPERMIN
- 1;
322 saved_seconds
= yourtm
.tm_sec
;
326 ** Divide the search space in half
327 ** (this works whether time_t is signed or unsigned).
329 bits
= TYPE_BIT(time_t) - 1;
331 ** Set t to the midpoint of our binary search.
333 ** If time_t is signed, then 0 is just above the median,
334 ** assuming two's complement arithmetic.
335 ** If time_t is unsigned, then (1 << bits) is just above the median.
337 t
= TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits
);
339 (*funcp
)(&t
, offset
, &mytm
); // Convert t to broken-down time in mytm
340 dir
= tmcomp(&mytm
, &yourtm
); // Is mytm larger, equal, or less than yourtm?
341 if (dir
!= 0) { // If mytm != yourtm...
342 if (bits
-- < 0) // If we have exhausted all the bits..
343 return WRONG
; // Return that we failed
344 if (bits
< 0) // If on the last bit...
345 --t
; /* may be needed if new t is minimal */
346 else if (dir
> 0) // else if mytm > yourtm...
347 t
-= ((time_t) 1) << bits
; // subtract half the remaining time-space
348 else t
+= ((time_t) 1) << bits
; // otherwise add half the remaining time-space
349 continue; // Repeat for the next half
351 if (yourtm
.tm_isdst
< 0 || mytm
.tm_isdst
== yourtm
.tm_isdst
)
354 ** Right time, wrong type.
355 ** Hunt for right time, right type.
356 ** It's okay to guess wrong since the guess
360 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
362 sp
= (const struct state
*)
363 (((void *) funcp
== (void *) localsub
) ?
368 #endif /* defined ALL_STATE */
369 for (i
= sp
->typecnt
- 1; i
>= 0; --i
) {
370 if (sp
->ttis
[i
].tt_isdst
!= yourtm
.tm_isdst
)
372 for (j
= sp
->typecnt
- 1; j
>= 0; --j
) {
373 if (sp
->ttis
[j
].tt_isdst
== yourtm
.tm_isdst
)
375 newt
= t
+ sp
->ttis
[j
].tt_gmtoff
-
376 sp
->ttis
[i
].tt_gmtoff
;
377 (*funcp
)(&newt
, offset
, &mytm
);
378 if (tmcomp(&mytm
, &yourtm
) != 0)
380 if (mytm
.tm_isdst
!= yourtm
.tm_isdst
)
392 newt
= t
+ saved_seconds
;
393 if ((newt
< t
) != (saved_seconds
< 0))
396 (*funcp
)(&t
, offset
, tmp
);
402 time2(struct tm
* const tmp
, void (* const funcp
)(const time_t*, long, struct tm
*),
403 const long offset
, int * const okayp
)
408 ** First try without normalization of seconds
409 ** (in case tm_sec contains a value associated with a leap second).
410 ** If that fails, try with normalization of seconds.
412 t
= time2sub(tmp
, funcp
, offset
, okayp
, FALSE
);
413 return *okayp
? t
: time2sub(tmp
, funcp
, offset
, okayp
, TRUE
);
418 struct tm
* const tmp
,
419 void (* const funcp
)(const time_t *, long, struct tm
*),
424 register const struct state
* sp
;
425 register int samei
, otheri
;
426 register int sameind
, otherind
;
429 int seen
[TZ_MAX_TYPES
];
430 int types
[TZ_MAX_TYPES
];
433 if (tmp
->tm_isdst
> 1)
435 t
= time2(tmp
, funcp
, offset
, &okay
);
438 ** PCTS code courtesy Grant Sullivan (grant@osf.org).
442 if (tmp
->tm_isdst
< 0)
443 tmp
->tm_isdst
= 0; /* reset to std and try again */
444 #endif /* defined PCTS */
446 if (okay
|| tmp
->tm_isdst
< 0)
448 #endif /* !defined PCTS */
450 ** We're supposed to assume that somebody took a time of one type
451 ** and did some math on it that yielded a "struct tm" that's bad.
452 ** We try to divine the type they started from and adjust to the
456 ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
458 sp
= (const struct state
*) (((void *) funcp
== (void *) localsub
) ?
463 #endif /* defined ALL_STATE */
464 for (i
= 0; i
< sp
->typecnt
; ++i
)
467 for (i
= sp
->timecnt
- 1; i
>= 0; --i
)
468 if (!seen
[sp
->types
[i
]]) {
469 seen
[sp
->types
[i
]] = TRUE
;
470 types
[nseen
++] = sp
->types
[i
];
472 for (sameind
= 0; sameind
< nseen
; ++sameind
) {
473 samei
= types
[sameind
];
474 if (sp
->ttis
[samei
].tt_isdst
!= tmp
->tm_isdst
)
476 for (otherind
= 0; otherind
< nseen
; ++otherind
) {
477 otheri
= types
[otherind
];
478 if (sp
->ttis
[otheri
].tt_isdst
== tmp
->tm_isdst
)
480 tmp
->tm_sec
+= (int)(sp
->ttis
[otheri
].tt_gmtoff
-
481 sp
->ttis
[samei
].tt_gmtoff
);
482 tmp
->tm_isdst
= !tmp
->tm_isdst
;
483 t
= time2(tmp
, funcp
, offset
, &okay
);
486 tmp
->tm_sec
-= (int)(sp
->ttis
[otheri
].tt_gmtoff
-
487 sp
->ttis
[samei
].tt_gmtoff
);
488 tmp
->tm_isdst
= !tmp
->tm_isdst
;
494 /** The mktime function converts the broken-down time, expressed as local time,
495 in the structure pointed to by timeptr into a calendar time value with the
496 same encoding as that of the values returned by the time function. The
497 original values of the tm_wday and tm_yday components of the structure are
498 ignored, and the original values of the other components are not restricted
499 to the ranges indicated above. Thus, a positive or zero value for tm_isdst
500 causes the mktime function to presume initially that Daylight Saving Time,
501 respectively, is or is not in effect for the specified time. A negative
502 value causes it to attempt to determine whether Daylight Saving Time is in
503 effect for the specified time. On successful completion, the values of the
504 tm_wday and tm_yday components of the structure are set appropriately, and
505 the other components are set to represent the specified calendar time, but
506 with their values forced to the ranges indicated above; the final value of
507 tm_mday is not set until tm_mon and tm_year are determined.
509 @return The mktime function returns the specified calendar time encoded
510 as a value of type time_t. If the calendar time cannot be
511 represented, the function returns the value (time_t)(-1).
514 mktime(struct tm
*timeptr
)
519 rwlock_wrlock(&lcl_lock
);
521 result
= time1(timeptr
, &localsub
, 0L);
522 rwlock_unlock(&lcl_lock
);
526 /** The time function determines the current calendar time. The encoding of
527 the value is unspecified.
529 @return The time function returns the implementation's best approximation
530 to the current calendar time. The value (time_t)(-1) is returned
531 if the calendar time is not available. If timer is not a null
532 pointer, the return value is also assigned to the object it
543 ET
= &gMD
->TimeBuffer
;
547 Status
= gRT
->GetTime( ET
, NULL
);
548 // Status = EfiGetTime( ET, NULL);
550 if( Status
!= RETURN_SUCCESS
) {
554 // Convert EFI time to broken-down time.
558 CalTime
= mktime(&gMD
->BDTime
);
563 return CalTime
; // Return calendar time in microseconds
566 /** The clock function determines the processor time used.
568 @return The clock function returns the implementation's best
569 approximation to the processor time used by the program since the
570 beginning of an implementation-defined era related only to the
571 program invocation. To determine the time in seconds, the value
572 returned by the clock function should be divided by the value of
573 the macro CLOCKS_PER_SEC. If the processor time used is not
574 available or its value cannot be represented, the function
575 returns the value (clock_t)(-1).
584 retval
= ((clock_t)((UINT32
)temp
)) - gMD
->AppStartTime
;
588 /* ################# Time Conversion Functions ########################## */
590 Except for the strftime function, these functions each return a pointer to
591 one of two types of static objects: a broken-down time structure or an
592 array of char. Execution of any of the functions that return a pointer to
593 one of these object types may overwrite the information in any object of
594 the same type pointed to by the value returned from any previous call to
595 any of them. The implementation shall behave as if no other library
596 functions call these functions.
599 /** The asctime function converts the broken-down time in the structure pointed
600 to by timeptr into a string in the form
601 Sun Sep 16 01:03:52 1973\n\0
602 using the equivalent of the following algorithm.
604 char *asctime(const struct tm *timeptr)
606 static const char wday_name[7][3] = {
607 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
609 static const char mon_name[12][3] = {
610 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
611 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
613 static char result[26];
614 sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
615 wday_name[timeptr->tm_wday],
616 mon_name[timeptr->tm_mon],
617 timeptr->tm_mday, timeptr->tm_hour,
618 timeptr->tm_min, timeptr->tm_sec,
619 1900 + timeptr->tm_year);
622 @return The asctime function returns a pointer to the string.
625 asctime(const struct tm
*timeptr
)
627 register const char * wn
;
628 register const char * mn
;
630 if (timeptr
->tm_wday
< 0 || timeptr
->tm_wday
>= DAYSPERWEEK
)
632 else wn
= wday_name
[timeptr
->tm_wday
];
633 if (timeptr
->tm_mon
< 0 || timeptr
->tm_mon
>= MONSPERYEAR
)
635 else mn
= mon_name
[timeptr
->tm_mon
];
637 ** The X3J11-suggested format is
638 ** "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"
639 ** Since the .2 in 02.2d is ignored, we drop it.
641 (void)snprintf(gMD
->ASasctime
,
642 sizeof (char[ASCTIME_BUFLEN
]),
643 "%.3s %.3s%3d %02d:%02d:%02d %d\r\n", // explicit CRLF for EFI
645 timeptr
->tm_mday
, timeptr
->tm_hour
,
646 timeptr
->tm_min
, timeptr
->tm_sec
,
647 TM_YEAR_BASE
+ timeptr
->tm_year
);
648 return gMD
->ASasctime
;
654 ctime(const time_t *timer
)
656 return asctime(localtime(timer
));
660 ** gmtsub is to gmtime as localsub is to localtime.
664 const time_t * const timep
,
666 struct tm
* const tmp
670 static mutex_t gmt_mutex
= MUTEX_INITIALIZER
;
673 mutex_lock(&gmt_mutex
);
677 gmtptr
= (struct state
*) malloc(sizeof *gmtptr
);
679 #endif /* defined ALL_STATE */
682 mutex_unlock(&gmt_mutex
);
683 timesub(timep
, offset
, gmtptr
, tmp
);
686 ** Could get fancy here and deliver something such as
687 ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero,
688 ** but this is no time for a treasure hunt.
691 tmp
->TM_ZONE
= (__aconst
char *)__UNCONST(wildabbr
);
695 tmp
->TM_ZONE
= (__aconst
char *)__UNCONST(gmt
);
696 else tmp
->TM_ZONE
= gmtptr
->chars
;
697 #endif /* defined ALL_STATE */
699 tmp
->TM_ZONE
= gmtptr
->chars
;
700 #endif /* State Farm */
702 #endif /* defined TM_ZONE */
708 gmtime(const time_t *timer
)
710 gmtsub(timer
, 0L, &gMD
->BDTime
);
715 localsub(const time_t * const timep
, const long offset
, struct tm
* const tmp
)
717 register struct state
* sp
;
718 register const struct ttinfo
* ttisp
;
720 const time_t t
= *timep
;
725 gmtsub(timep
, offset
, tmp
);
728 #endif /* defined ALL_STATE */
729 if (sp
->timecnt
== 0 || t
< sp
->ats
[0]) {
731 while (sp
->ttis
[i
].tt_isdst
)
732 if (++i
>= sp
->typecnt
) {
737 for (i
= 1; i
< sp
->timecnt
; ++i
)
740 i
= sp
->types
[i
- 1];
742 ttisp
= &sp
->ttis
[i
];
744 ** To get (wrong) behavior that's compatible with System V Release 2.0
745 ** you'd replace the statement below with
746 ** t += ttisp->tt_gmtoff;
747 ** timesub(&t, 0L, sp, tmp);
749 timesub(&t
, ttisp
->tt_gmtoff
, sp
, tmp
);
750 tmp
->tm_isdst
= ttisp
->tt_isdst
;
751 tzname
[tmp
->tm_isdst
] = &sp
->chars
[ttisp
->tt_abbrind
];
753 tmp
->TM_ZONE
= &sp
->chars
[ttisp
->tt_abbrind
];
754 #endif /* defined TM_ZONE */
760 localtime(const time_t *timer
)
763 localsub(timer
, 0L, &gMD
->BDTime
);