Section 18.1. Telling Time and Dates

   


18.1. Telling Time and Dates

18.1.1. Representing Time

Unix and Linux keep track of time in seconds before or after the epoch, which is defined as midnight, January 1, 1970 UTC.[1] Positive time values are after the epoch; negative time values are before the epoch. In order to provide processes with the current time, Linux, like all versions of Unix, provides a system call called time():

[1] UTC: Universal Coordinated Time, also sometimes improperly referred to as UCT; roughly equivalent to Greenwich Mean Time (GMT) and Zulu. Time zone designations involve technical detail far beyond the scope of this book.

 #include <time.h> time_t time(time_t *t); 


time() returns the number of seconds since the epoch, and if t is non-null, it also fills in t with the number of seconds since the epoch.

Some problems require higher resolution. Linux provides another system call, gettimeofday(), which provides more information:

 #include <sys/time.h> #include <unistd.h> int gettimeofday(struct timeval *tv, struct timezone *tz); struct timeval {     int tv_sec;         /* seconds */     int tv_usec;        /* microseconds */ }; struct timezone {     int tz_minuteswest; /* minutes west of Greenwich */     int tz_dsttime;     /* type of dst correction */ }; 


On most platforms, including the i386 platform, Linux is able to provide very accurate time measurements. Industry-standard PCs have a hardware clock that provides microsecond-accurate time information. Alpha and SPARC hardware also provides a high-resolution timer. On some other platforms, however, Linux can keep track of time only within the resolution of the system timer, which is generally set to 100Hz, so the tv_usec member of the timeval structure may be less accurate on those systems.

Five macros are provided in sys/time.h for operating on timeval structures:

 timerclear(struct timeval *) 


This clears a timeval structure.

 timerisset(struct timeval *) 


This checks to see if a timeval structure has been filled in (that is, if either element is nonzero).

 timercmp(struct timeval *t0, struct timeval *t1, operator) 


This allows you to compare two timeval structures in the time domain. It evaluates the logical equivalent of t0 operator t1, if t0 and t1 were arithmetic types. Note that timercmp() does not work for the <= and >= operators. Use !timercmp(t1, t2, >) and !timercmp(t1, t2, <) instead.

 timeradd(struct timeval *t0, struct timeval *t1, struct timeval *result) 


Adds t0 to t1 and places the sum in result.

 timersub(struct timeval *t0, struct timeval *t1, struct timeval *result) 


Subtracts t1 from t0 and places the difference in result.

A third representation of time, struct tm, puts the time in terms that are more human-oriented:

 struct tm { {     int tm_sec;     int tm_min;     int tm_hour;     int tm_mday;     int tm_mon;     int tm_year;     int tm_wday;     int tm_yday;     int tm_isdst;     long int tm_gmtoff;     const char *tm_zone; }; 


The first nine elements are standard; the final two are nonstandard but useful when they exist, as they do on Linux systems.

tm_sec

The number of elapsed seconds in the minute. Will be between 0 and 61 (two extra seconds are allocated to deal with leap seconds).

tm_min

The number of elapsed minutes in the hour. Will be between 0 and 59.

tm_hour

The number of elapsed hours in the day. Will be between 0 and 23.

tm_mday

The number of the day of the month. Will be between 1 and 31. This is the only member that will never be 0.

tm_mon

The number of elapsed months in the year. Will be between 0 and 11.

tm_year

The number of elapsed years since 1900.

tm_wday

The number of elapsed days in the week (since Sunday). Will be between 0 and 6.

tm_yday

The number of elapsed days in the year. Will be between 0 and 365.

tm_isdst

Whether some sort of daylight savings time is in effect in the expressed time value in the current time zone, if applicable. tm_isdst will be positive if daylight savings time is in effect,0 if it is not in effect, and -1 if the system does not know.

tm_gmtoff

This is not portable as it does not exist on all systems. If it exists, it may also be named _ _tm_gmtoff. It specifies seconds east of UTC or negative seconds west of UTC for time zones east of the date line.

tm_zone

This is not portable as it does not exist on all systems. If it exists, it may also be named _ _tm_zone. It holds a name for the current time zone (some time zones may have several names).


Finally, the POSIX.1b real-time processing standard allows even higher resolution than the microsecond resolution available in struct timeval. struct timespec uses nanoseconds instead and provides larger places to put the numbers:

 struct timespec {     long int tv_sec;   /* seconds     */     long int tv_nsec;  /* nanoseconds */ }; 


18.1.2. Converting, Formatting, and Parsing Times

Four functions are available for converting among times expressed in terms of time_t and times expressed in terms of struct tm. Three are standard and are available on all Linux and Unix systems. The fourth, although useful, is not universally available, although it is available on all current Linux systems. A fifth function, which is standard, calculates the difference in seconds between time_t times. (Notice that even the time_t arguments are passed as pointers, not just the struct tm arguments.)

 struct tm * gmtime(const time_t *t) 


Short for Greenwich Mean Time, gmtime() converts a time_t value into a struct tm that expresses that time in UTC.

 struct tm * localtime(const time_t *t) 


localtime() acts like gmtime() except that it creates the struct tm expressed in terms of local time. Local time is defined for the whole system by the settings of the zoneinfo files, and that can be overridden by a TZ environment variable by users who are working from a different time zone than the one the computer is in.

 time_t mktime(struct tm *tp); 


mktime() converts a struct tm to a time_t, assuming that the struct tm is expressed in terms of local time.

 time_t timegm(struct tm *tp); 


timegm() acts like mktime() except that it assumes that the struct tm is expressed in terms of UTC. It is not a standard function.

 double difftime(time_t time1, time_t time0); 


difftime() returns a floating-point number representing the difference in time in seconds between two time_t values. Although time_t is guaranteed to be an arithmetic type, the unit is not specified by ANSI/ISO C; difftime() returns the difference in seconds, regardless of the units of time_t.

Four more functions are available to convert time between computer-friendly numbers and human-friendly textual representations. Again, the final one is not standard, despite its obvious general usefulness.

 char *asctime(struct tm *tp); char *ctime(time_t *t); 


asctime() and ctime() both convert a time value into a standard Unix date string that looks something like this:

 Tue Jun 17 23:17:29 1997 


In both cases, the string is 26 characters long and includes a final newline character and the terminating '\0'.

The length of the string may not be guaranteed to be 26 characters in all locales, as it is in the default C locale.

ctime() expresses this date in local time. asctime() expresses this date in whatever time zone the struct tm specifies; if it was created with gmtime(), it is in UTC, but if it was created with localtime(), it is in local time.

 size_t strftime(char *s, size_t max, char *fmt, struct tm *tp); 


strftime() is like sprintf() for time. It formats a struct tm according to the format fmt and places the result in no more than max bytes (including the terminating '\0') of the string s.

Like sprintf(), strftime() uses the % character to introduce escape sequences into which data is substituted. All of the substituted strings are expressed in terms of the current locale. However, the escape sequences are completely different. In several cases, lowercase letters are used for abbreviations and uppercase letters are used for full names. Unlike sprintf(), you do not have the option of using numbers in the middle of an escape sequence to limit the length of the substituted string; %. 6 A is invalid. Like sprintf(), strftime() returns the number of characters printed into the s buffer. If it is equal to max, the buffer is not large enough for the current locale; allocate a larger buffer and try again.

strftime() uses the same substitutions used by the date program. These definitions of the substitutions are for the default locale and are here to help you identify the type of information they provide; they may be somewhat different in other locales.

%a

The three-character abbreviation for the name of the weekday.

%A

The full name of the weekday.

%b

The three-character abbreviation for the name of the month.

%B

The full name of the month.

%c

The preferred local expression of the date and time, as returned by ctime() and asctime().

%d

The numeric day of the month, counting from zero.

%H

The hour of the day, in 24-hour time, counting from zero.

%I

The hour of the day, in 12-hour time, counting from zero.

%j

The day of the year, counting from one.

%m

The month of the year, counting from one.

%M

The minute of the hour, counting from zero.

%p

The correct string for the local equivalent of AM or PM.

%S

The second of the minute, counting from zero.

%U

The numeric week of the year, where week one starts on the first Sunday of the year.

%W

The numeric week of the year, where week one starts on the first Monday of the year.

%w

The numeric day of the week, counting from zero.

%x

The preferred local expression of the date only, without the time.

%X

The preferred local expression of the time only, without the date.

%y

The two-digit representation of the year, without the century. (Do not use this it is a potent source of year-2000 problems.)

%Y

The full four-digit numeric representation of the year.

%Z

The name or standard abbreviation of the time zone.

%%

The literal character %.


 char *strptime(char *s, char *fmt, struct tm *tp); 


Like scanf(), strptime() converts a string to a parsed format. It tries to be liberal in interpreting the s input string according to the fmt format string. It takes the same escape sequences that strftime() takes, but for each type of input, it accepts both abbreviations and full names. It does not distinguish between upper and lower case, and it does not recognize %U and %W.

strptime() also provides a few extra escape sequences and interprets a few sequences slightly differently than does strftime(). Only the significantly different escape sequences (that is, beyond the changes already mentioned) are documented in this list. Numbers may have leading zeros, but they are not required.

%h

Equivalent to %b and %B.

%c

Reads the date and time as printed by strftime() with the format string %x %X.

%C

Reads the date and time as printed by strftime() with the format string %c.

%e

Equivalent to %d.

%D

Reads the date as printed by strftime() with the format string %m/%d/%y.

%k

Equivalent to %H.

%l

Equivalent to %I.

%r

Reads the time as printed by strftime() with the format string %I:%M:%S %p.

%R

Reads the time as printed by strftime() with the format string %H:%M.

%T

Reads the time as printed by strftime() with the format string %H:%M:%S.

%y

Reads the year within the twentieth century. 1900 is added to the value, and only values of 0-99 are allowed.

%Y

Reads the full year. Use this instead of %y if you possibly can, to avoid year-2000 problems.


strptime() returns a pointer to the character in s one character beyond the final character that it reads while parsing.

The strptime() function is, unfortunately, specified neither by ANSI/ISO nor POSIX, which limits its portability.

18.1.3. The Limits of Time

On 32-bit Linux systems, like most Unix systems, time_t is a signed integer 32 bits long. This means that it will overflow Monday, January 18, 2038, at 10:14:07 PM. So Monday, January 18, 2038, 10:14:08 PM will be represented as Friday, December 13th, 3:45:52 PM, 1901. As you can see, Linux did not exhibit a year-2000 problem (as far as the native time libraries are concerned), but it does have a year-2038 problem.

On 64-bit platforms, time_t is instead a 64-bit signed long. This is effectively forever; signed 64-bit time is truly astronomical, as it will not overflow until well after the sun is predicted to envelop the Earth as it becomes a red giant.

To find the beginning of time, the current time, and the end of time for the system you are using, you can build and run this program, daytime.c:

  1: /* daytime.c */  2:  3: #include <stdio.h>  4: #include <sys/time.h>  5: #include <unistd.h>  6:  7: int main() {  8:     struct timeval tv;  9:     struct timezone tz; 10:     time_t now; 11:     /* beginning_of_time is smallest time_t-sized value */ 12:     time_t beginning_of_time = 1L<<(sizeof(time_t)*8 - 1); 13:     /* end_of_time is largest time_t-sized value */ 14:     time_t end_of_time = ~beginning_of_time; 15: 16:     printf("time_t is %d bits long\n\n", sizeof(time_t)*8); 17: 18:     gettimeofday(&tv, &tz); 19:     now = tv.tv_sec; 20:     printf("Current time of day represented as a struct timeval:\n" 21:            "tv.tv_sec = 0x%08x, tv.tv_usec = 0x%08x\n" 22:           "tz.tz_minuteswest = 0x%08x, tz.tz_dsttime = 0x%08x\n\n", 23:           tv.tv_sec, tv.tv_usec, tz.tz_minuteswest, tz.tz_dsttime); 24: 25:     printf("Demonstrating ctime()%s:\n", 26:            sizeof(time_t)*8 <= 32 ? "": 27:            " (may hang after printing first line; press " 28:            "control-C)"); 29:     printf("time is now %s", ctime(&now)); 30:     printf("time begins %s", ctime(&beginning_of_time)); 31:     printf("time ends %s", ctime(&end_of_time)); 32: 33:     exit (0); 34: } 


Unfortunately, the ctime() function is iterative by nature, which means that it (for all practical purposes) never terminates on 64-bit systems for astronomical dates like the 64-bit beginning and end of time. Use Control-C to terminate the program when you become tired of waiting for it to complete.


       
    top
     


    Linux Application Development
    Linux Application Development (paperback) (2nd Edition)
    ISBN: 0321563220
    EAN: 2147483647
    Year: 2003
    Pages: 168

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net