需求如下:
Phil
As you know in North America we change time twice a year – 1 hour forward in Spring and 1 hour back in Fall.
This means all terminal users need to go in Date/time settings to change the time manually.
The time change happens 2nd Sunday of March (1 hour forward) at 2 am and 1st Sunday of November at 2 am (1 hour back).
Can this time change be automated in the kernel or app manager or OS level so the user doesn’t have to do this manually?
Shelly
解决方案
第一步:
copy或者ln -s一个属于夏令时的时区文件(如New_York)到/etc/localtime
int main(int argc, char** argv)
{
time_t currtime;
char ptchTime[30];
struct tm* pTm;
time(&currtime);
pTm = localtime(&currtime);
if (pTm)
{
sprintf(ptchTime, "%02d%02d%02d %02d%02d%02d[DST=%d]\n",
pTm->tm_year%100, pTm->tm_mon+1, pTm->tm_mday,
pTm->tm_hour, pTm->tm_min, pTm->tm_sec, pTm->tm_isdst);
}
printf(ptchTime);
struct tm tm_new;
time_t the_time;
tm_new.tm_year = 113; tm_new.tm_mon = 10; tm_new.tm_mday = 3;
tm_new.tm_hour = 1; tm_new.tm_min = 59; tm_new.tm_sec = 0;
printf("tm_new est=%d\n", tm_new.tm_isdst);
the_time=mktime(&tm_new);
//update system time
stime((long*)&the_time);
//update hardware time
system("hwclock -w");
time(&currtime);
pTm = localtime(&currtime);
if (pTm)
{
sprintf(ptchTime, "%02d%02d%02d %02d%02d%02d[DST=%d]\n",
pTm->tm_year%100, pTm->tm_mon+1, pTm->tm_mday,
pTm->tm_hour, pTm->tm_min, pTm->tm_sec, pTm->tm_isdst);
}
printf(ptchTime);
return 0;
}
memset((char*)&tm_new, 0 ,sizeof(struct tm));
Broken-down time is stored in the structure tm which is defined in as follows:
struct tm {
int tm_sec; /* seconds */
int tm_min; /* minutes */
int tm_hour; /* hours */
int tm_mday; /* day of the month */
int tm_mon; /* month */
int tm_year; /* year */
int tm_wday; /* day of the week */
int tm_yday; /* day in the year */
int tm_isdst; /* daylight saving time */
};
The members of the tm structure are:
tm_sec The number of seconds after the minute, normally in the range 0 to 59, but can be up to 60 to allow for leap seconds.
tm_min The number of minutes after the hour, in the range 0 to 59.
tm_hour The number of hours past midnight, in the range 0 to 23.
tm_mday The day of the month, in the range 1 to 31.
tm_mon The number of months since January, in the range 0 to 11.
tm_year The number of years since 1900.
tm_wday The number of days since Sunday, in the range 0 to 6.
tm_yday The number of days since January 1, in the range 0 to 365.
tm_isdst A flag that indicates whether daylight saving time is in effect at the time described. The value is positive if daylight saving time is
in effect, zero if it is not, and negative if the information is not available.
# date -s 110301592013
# date
Sun Nov 3 01:59:18 EDT 2013
# date
Sun Nov 3 01:59:54 EDT 2013
# date
Sun Nov 3 01:59:55 EDT 2013
# date
Sun Nov 3 01:59:58 EDT 2013
# date
Sun Nov 3 01:00:01 EST 2013
/* Now we have parsed all the information except the date format
which depends on whether the clock is being set or read */
if(filename) {
struct stat statbuf;
xstat(filename,&statbuf);
tm=statbuf.st_mtime;
} else time(&tm);
memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
/* Zero out fields - take her back to midnight! */
if (date_str != NULL) {
tm_time.tm_sec = 0;
tm_time.tm_min = 0;
tm_time.tm_hour = 0;
/* Process any date input to UNIX time since 1 Jan 1970 */
if (ENABLE_FEATURE_DATE_ISOFMT && (opt & DATE_OPT_HINT)) {
strptime(date_str, hintfmt_arg, &tm_time);
} else if (strchr(date_str, ':') != NULL) {
date_conv_ftime(&tm_time, date_str);
} else {
date_conv_time(&tm_time, date_str);
}
/* Correct any day of week and day of year etc. fields */
tm_time.tm_isdst = -1; /* Be sure to recheck dst. */
tm = mktime(&tm_time);
if (tm < 0) {
bb_error_msg_and_die(bb_msg_invalid_date, date_str);
}
if (utc && putenv("TZ=UTC0") != 0) {
bb_error_msg_and_die(bb_msg_memory_exhausted);
}
/* if setting time, set it */
if (set_time && stime(&tm) < 0) {
bb_perror_msg("cannot set date");
}
}
tm_time.tm_isdst = -1; /* Be sure to recheck dst. */
tm_isdst A flag that indicates whether daylight saving time is in effect at the time described. The value is positive if daylight saving time is
in effect, zero if it is not, and negative if the information is not available.
太难理解啊,google之,发现两篇文章:
struct tm tm_new;
time_t the_time;
memset((char*)&tm_new, 0 ,sizeof(struct tm));
tm_new.tm_year = 113; tm_new.tm_mon = 10; tm_new.tm_mday = 3;
tm_new.tm_hour = 1; tm_new.tm_min = 59; tm_new.tm_sec = 0;
tm_new.tm_isdst=-1;/* Be sure to recheck dst. */
printf("tm_new est=%d\n", tm_new.tm_isdst);
the_time=mktime(&tm_new);
//update system time
stime((long*)&the_time);
struct tm *localtime_r(const time_t *timer,struct tm *result){
struct tm *tm;
tm=localtime(timer);
memmove(result,tm,sizeof(tm));
return result;
}
/* Convert *TP to a time_t value, inverting
the monotonic and mostly-unit-linear conversion function CONVERT.
Use *OFFSET to keep track of a guess at the offset of the result,
compared to what the result would be for UTC without leap seconds.
If *OFFSET's guess is correct, only one CONVERT call is needed. */
#ifndef _LIBC
static
#endif
time_t
__mktime_internal (struct tm *tp,
struct tm *(*convert) (const time_t *, struct tm *),
time_t *offset)
{
time_t t, dt, t0, t1, t2;
struct tm tm;
/* The maximum number of probes (calls to CONVERT) should be enough
to handle any combinations of time zone rule changes, solar time,
leap seconds, and oscillations around a spring-forward gap.
POSIX.1 prohibits leap seconds, but some hosts have them anyway. */
int remaining_probes = 6;
/* Time requested. Copy it in case CONVERT modifies *TP; this can
occur if TP is localtime's returned value and CONVERT is localtime. */
int sec = tp->tm_sec;
int min = tp->tm_min;
int hour = tp->tm_hour;
int mday = tp->tm_mday;
int mon = tp->tm_mon;
int year_requested = tp->tm_year;
int isdst = tp->tm_isdst;
/* 1 if the previous probe was DST. */
int dst2;
/* Ensure that mon is in range, and set year accordingly. */
int mon_remainder = mon % 12;
int negative_mon_remainder = mon_remainder < 0;
int mon_years = mon / 12 - negative_mon_remainder;
int year = year_requested + mon_years;
/* The other values need not be in range:
the remaining code handles minor overflows correctly,
assuming int and time_t arithmetic wraps around.
Major overflows are caught at the end. */
/* Calculate day of year from year, month, and day of month.
The result need not be in range. */
int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
[mon_remainder + 12 * negative_mon_remainder])
+ mday - 1);
int sec_requested = sec;
/* Only years after 1970 are defined.
If year is 69, it might still be representable due to
timezone differences. */
if (year < 69)
return -1;
#if LEAP_SECONDS_POSSIBLE
/* Handle out-of-range seconds specially,
since ydhms_tm_diff assumes every minute has 60 seconds. */
if (sec < 0)
sec = 0;
if (59 < sec)
sec = 59;
#endif
/* Invert CONVERT by probing. First assume the same offset as last time.
Then repeatedly use the error to improve the guess. */
tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
for (t = t1 = t2 = t0 + *offset, dst2 = 0;
(dt = ydhms_tm_diff (year, yday, hour, min, sec,
ranged_convert (convert, &t, &tm)));
t1 = t2, t2 = t, t += dt, dst2 = tm.tm_isdst != 0)
if (t == t1 && t != t2
&& (tm.tm_isdst < 0
|| (isdst < 0
? dst2 <= (tm.tm_isdst != 0)
: (isdst != 0) != (tm.tm_isdst != 0))))
/* We can't possibly find a match, as we are oscillating
between two values. The requested time probably falls
within a spring-forward gap of size DT. Follow the common
practice in this case, which is to return a time that is DT
away from the requested time, preferring a time whose
tm_isdst differs from the requested value. (If no tm_isdst
was requested and only one of the two values has a nonzero
tm_isdst, prefer that value.) In practice, this is more
useful than returning -1. */
break;
else if (--remaining_probes == 0)
return -1;
/* If we have a match, check whether tm.tm_isdst has the requested
value, if any. */
if (dt == 0 && isdst != tm.tm_isdst && 0 <= isdst && 0 <= tm.tm_isdst)
{
/* tm.tm_isdst has the wrong value. Look for a neighboring
time with the right value, and use its UTC offset.
Heuristic: probe the previous three calendar quarters (approximately),
looking for the desired isdst. This isn't perfect,
but it's good enough in practice. */
int quarter = 7889238; /* seconds per average 1/4 Gregorian year */
int i;
/* If we're too close to the time_t limit, look in future quarters. */
if (t < TIME_T_MIN + 3 * quarter)
quarter = -quarter;
for (i = 1; i <= 3; i++)
{
time_t ot = t - i * quarter;
struct tm otm;
ranged_convert (convert, &ot, &otm);
if (otm.tm_isdst == isdst)
{
/* We found the desired tm_isdst.
Extrapolate back to the desired time. */
t = ot + ydhms_tm_diff (year, yday, hour, min, sec, &otm);
ranged_convert (convert, &t, &tm);
break;
}
}
}
*offset = t - t0;
#if LEAP_SECONDS_POSSIBLE
if (sec_requested != tm.tm_sec)
{
/* Adjust time to reflect the tm_sec requested, not the normalized value.
Also, repair any damage from a false match due to a leap second. */
t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
if (! (*convert) (&t, &tm))
return -1;
}
#endif
if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
{
/* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
so check for major overflows. A gross check suffices,
since if t has overflowed, it is off by a multiple of
TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
the difference that is bounded by a small value. */
double dyear = (double) year_requested + mon_years - tm.tm_year;
double dday = 366 * dyear + mday;
double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
/* On Irix4.0.5 cc, dividing TIME_T_MIN by 3 does not produce
correct results, ie., it erroneously gives a positive value
of 715827882. Setting a variable first then doing math on it
seems to work. ([email protected]) */
const time_t time_t_max = TIME_T_MAX;
const time_t time_t_min = TIME_T_MIN;
if (time_t_max / 3 - time_t_min / 3 < (dsec < 0 ? - dsec : dsec))
return -1;
}
if (year == 69)
{
/* If year was 69, need to check whether the time was representable
or not. */
if (t < 0 || t > 2 * 24 * 60 * 60)
return -1;
}
*tp = tm;
return t;
}
static time_t localtime_offset;
/* Convert *TP to a time_t value. */
time_t
mktime (tp)
struct tm *tp;
{
#ifdef _LIBC
/* POSIX.1 8.1.1 requires that whenever mktime() is called, the
time zone names contained in the external variable `tzname' shall
be set as if the tzset() function had been called. */
__tzset ();
#endif
return __mktime_internal (tp, my_mktime_localtime_r, &localtime_offset);
}