在设备应用中,用户需要根据自己的时区设置设备时区。在可交互的系统中或者完整的linux系统中可以通过设置/etc/TZ等时区文件链接的文件来修改设备时区。但是在一些rtos或者不能使用上面设置TZ文件方式的系统中,可以通过设置应用进程的TZ环境变量的方式来设置时区,此时在通过localtime等函数转换的时间就是本地时间了。
效果展示$ make test ./timezone Europe/London ts 1647169200, date 2022-03-13 11:00:00 America/Anchorage ts 1647169199, date 2022-03-13 01:59:59 America/Anchorage ts 1647169200, date 2022-03-13 03:00:00 Australia/Adelaide ts 1647169200, date 2022-03-13 21:30:00 Europe/London ts 1648917000, date 2022-04-02 17:30:00 America/Anchorage ts 1648917000, date 2022-04-02 08:30:00 Australia/Adelaide ts 1648916999, date 2022-04-03 02:59:59 Australia/Adelaide ts 1648917000, date 2022-04-03 02:00:00代码展示
citylist.h
#ifndef __CITYLIST_H_
#define __CITYLIST_H_
static const char cityList[][2][128]={
{ "Pacific/Midway", "SST11" },
{ "Pacific/Honolulu", "HST10" },
{ "America/Anchorage", "AKST9AKDT,M3.2.0,M11.1.0" },
{ "America/Los_Angeles", "PST8PDT,M3.2.0,M11.1.0" },
{ "America/Tijuana", "PST8PDT,M3.2.0,M11.1.0" },
{ "America/Phoenix", "MST7" },
{ "America/Chihuahua", "MST7MDT,M4.1.0,M10.5.0" },
{ "America/Denver", "MST7MDT,M3.2.0,M11.1.0" },
{ "America/Costa_Rica", "CST6" },
{ "America/Chicago", "CST6CDT,M3.2.0,M11.1.0" },
{ "America/Mexico_City", "CST6CDT,M4.1.0,M10.5.0" },
{ "America/Regina", "CST6" },
{ "America/Bogota", "<-05>5" },
{ "America/New_York", "EST5EDT,M3.2.0,M11.1.0" },
{ "America/Caracas", "<-04>4" },
{ "America/Barbados", "AST4" },
{ "America/Halifax", "AST4ADT,M3.2.0,M11.1.0" },
{ "America/Manaus", "<-04>4" },
{ "America/Santiago", "" },
{ "America/St_Johns", "NST3:30NDT,M3.2.0,M11.1.0" },
{ "America/Sao_Paulo", "<-03>3" },
{ "America/Argentina/Buenos_Aires", "<-03>3" },
{ "America/Godthab", "" },
{ "America/Montevideo", "<-03>3" },
{ "Atlantic/South_Georgia", "<-02>2" },
{ "Atlantic/Azores", "<-01>1<+00>,M3.5.0/0,M10.5.0/1" },
{ "Atlantic/Cape_Verde", "<-01>1" },
{ "Africa/Casablanca", "<+01>-1" },
{ "Europe/London", "GMT0BST,M3.5.0/1,M10.5.0" },
{ "Europe/Amsterdam", "CET-1CEST,M3.5.0,M10.5.0/3" },
{ "Europe/Belgrade", "CET-1CEST,M3.5.0,M10.5.0/3" },
{ "Europe/Brussels", "CET-1CEST,M3.5.0,M10.5.0/3" },
{ "Europe/Sarajevo", "CET-1CEST,M3.5.0,M10.5.0/3" },
{ "Africa/Windhoek", "CAT-2" },
{ "Africa/Brazzaville", "WAT-1" },
{ "Asia/Amman", "EET-2EEST,M3.5.4/24,M10.5.5/1" },
{ "Europe/Athens", "EET-2EEST,M3.5.0/3,M10.5.0/4" },
{ "Europe/Istanbul", "<+03>-3" },
{ "Asia/Beirut", "EET-2EEST,M3.5.0/0,M10.5.0/0" },
{ "Africa/Cairo", "EET-2" },
{ "Europe/Helsinki", "EET-2EEST,M3.5.0/3,M10.5.0/4" },
{ "Asia/Jerusalem", "" },
{ "Europe/Minsk", "<+03>-3" },
{ "Africa/Harare", "CAT-2" },
{ "Asia/Baghdad", "<+03>-3" },
{ "Europe/Moscow", "MSK-3" },
{ "Asia/Kuwait", "<+03>-3" },
{ "Africa/Nairobi", "EAT-3" },
{ "Asia/Tehran", "<+0330>-3:30<+0430>,J79/24,J263/24" },
{ "Asia/Baku", "<+04>-4" },
{ "Asia/Tbilisi", "<+04>-4" },
{ "Asia/Yerevan", "<+04>-4" },
{ "Asia/Dubai", "<+04>-4" },
{ "Asia/Kabul", "<+0430>-4:30" },
{ "Asia/Karachi", "PKT-5" },
{ "Asia/Oral", "<+05>-5" },
{ "Asia/Yekaterinburg", "<+05>-5" },
{ "Asia/Calcutta", "IST-5:30" },
{ "Asia/Colombo", "<+0530>-5:30" },
{ "Asia/Katmandu", "<+0545>-5:45" },
{ "Asia/Almaty", "<+06>-6" },
{ "Asia/Rangoon", "<+0630>-6:30" },
{ "Asia/Krasnoyarsk", "<+07>-7" },
{ "Asia/Bangkok", "<+07>-7" },
{ "Asia/Jakarta", "WIB-7" },
{ "Asia/Shanghai", "CST-8" },
{ "Asia/Hong_Kong", "HKT-8" },
{ "Asia/Irkutsk", "<+08>-8" },
{ "Asia/Kuala_Lumpur", "<+08>-8" },
{ "Australia/Perth", "AWST-8" },
{ "Asia/Taipei", "CST-8" },
{ "Asia/Seoul", "KST-9" },
{ "Asia/Tokyo", "JST-9" },
{ "Asia/Yakutsk", "<+09>-9" },
{ "Australia/Adelaide", "ACST-9:30ACDT,M10.1.0,M4.1.0/3" },
{ "Australia/Darwin", "ACST-9:30" },
{ "Australia/Brisbane", "AEST-10" },
{ "Australia/Hobart", "AEST-10AEDT,M10.1.0,M4.1.0/3" },
{ "Australia/Sydney", "AEST-10AEDT,M10.1.0,M4.1.0/3" },
{ "Asia/Vladivostok", "<+10>-10" },
{ "Pacific/Guam", "ChST-10" },
{ "Asia/Magadan", "<+11>-11" },
{ "Pacific/Majuro", "<+12>-12" },
{ "Pacific/Auckland", "NZST-12NZDT,M9.5.0,M4.1.0/3" },
{ "Pacific/Fiji", "" },
{ "Pacific/Tongatapu", "<+13>-13" }
};
#endif
main.c
#include#include #include #include #include "citylist.h" int setTimeZone( const char *pRegion ) { int ret = 0; for( int i=0; i if( strcmp( pRegion, cityList[i][0] ) == 0 ){ setenv( "TZ", cityList[i][1], 1 ); break; } } tzset(); return ret; } void printTime( const char *pRegion, time_t ts ) { setTimeZone(pRegion); struct tm *date = localtime( &ts ); printf("%-20s ts %lu, date %4d-%02d-%02d %02d:%02d:%02dn", pRegion, ts, date->tm_year+1900, date->tm_mon+1, date->tm_mday, date->tm_hour, date->tm_min, date->tm_sec); } int main() { time_t ts; ts = 1647169200; printTime( "Europe/London", ts ); printTime( "America/Anchorage", ts-1 ); printTime( "America/Anchorage", ts ); printTime( "Australia/Adelaide", ts ); printf("nn"); ts = 1648917000; printTime( "Europe/London", ts ); printTime( "America/Anchorage", ts ); printTime( "Australia/Adelaide", ts-1 ); printTime( "Australia/Adelaide", ts ); return 0; }
Makefile
taget=timezone all: $(taget) $(taget): main.c gcc -o $@ $^ test: $(taget) ./$(taget) clean: rm $(taget)拓展
其中citylist.h中的城市列表中的环境变量是从linux的时区文件中提取的。
提取环境变量的代码为:
tzif-display.c
#define _GNU_SOURCE #define _POSIX_C_SOURCE #include/// For printf, fopen, fclose, FILE #include /// For malloc, free #include /// For error #include /// For errno #include /// for memset, memcpy, memmem #include /// for stat #include /// for setlocale #include /// for ctime_r, tzset #define TRUE -1 #define FALSE 0 #define HEADER_LEN 44 typedef struct { char magicnumber[6]; // = TZif2 or TZif // char reserved[15]; // nulls long unsigned ttisgmtcnt; // number of UTC/local indicators stored in the file. long unsigned ttisstdcnt; // number of standard/wall indicators stored in the file. long unsigned leapcnt; // number of leap seconds for which data is stored in the file. long unsigned timecnt; // number of "transition times" for which data is stored in the file. long unsigned typecnt; // number of "local time types" for which data is stored in the file (must not be zero). long unsigned charcnt; // number of characters of "timezone abbreviation strings" stored in the file. } timezonefileheader; #define TZIF1_FIELD_SIZE 4 #define TZIF2_FIELD_SIZE 8 long parse_tz_long( const char *sourceptr, const int field_size) { long retval = 0; char *long_ptr; // if (sizeof(long) < field_size) // printf("warning: field truncated because it is larger than a 'long' integernn"); int i,j; long_ptr = (char*) &retval; if ((field_size < sizeof(long)) && (sourceptr[0] >> 8)) { for (i=sizeof(long)-1; (i>=field_size); i--) long_ptr[i] = 255; } j = 0; for (i=field_size-1; (i>=0) && (j long_ptr[j] = sourceptr[i]; j++; } return retval; } int read_tz_header( timezonefileheader *header, const char *temp_buffer) { const int field_size = 4; memcpy( header->magicnumber, &temp_buffer[0], 5 ); header->magicnumber[5] = ' '; header->ttisgmtcnt = parse_tz_long(&temp_buffer[20], field_size); header->ttisstdcnt = parse_tz_long(&temp_buffer[24], field_size); header->leapcnt = parse_tz_long(&temp_buffer[28], field_size); header->timecnt = parse_tz_long(&temp_buffer[32], field_size); header->typecnt = parse_tz_long(&temp_buffer[36], field_size); header->charcnt = parse_tz_long(&temp_buffer[40], field_size); if (header->typecnt == 0) { printf("Error in file format. Zero local time types suggested.n"); return FALSE; } if (header->timecnt == 0) { printf("No transition times recorded in this filen"); return FALSE; } return TRUE; } char* tzif2_handle( timezonefileheader *tzh, const char *tzfile_buffer_ptr, size_t buffer_size ) { char *start_ptr; char magicnumber[5] = "TZif2"; start_ptr = memmem( tzfile_buffer_ptr, buffer_size, &magicnumber, 5 ); if (start_ptr == NULL) { printf("error finding tzif2 headern"); return NULL; } if ( read_tz_header( tzh, (char*) start_ptr ) == FALSE ) { printf("Error reading header file version 2n"); return NULL; } return start_ptr + HEADER_LEN; } void handle_tzfile_data( char *tz, const timezonefileheader tzh, const char* tzfile_buffer_ptr, const int field_size /// 4bytes for tzif1, 8bytes for tzif2 ) { char *local_time_type_ptr; char *ttinfo_read_ptr; char* tz_abbrev_ptr; char *leapinfo_ptr; char *wall_indicator_ptr; char *local_indicator_ptr; local_time_type_ptr = (char*) tzfile_buffer_ptr + tzh.timecnt*field_size; ttinfo_read_ptr = local_time_type_ptr + tzh.timecnt; tz_abbrev_ptr = ttinfo_read_ptr + (tzh.typecnt * 6); leapinfo_ptr = tz_abbrev_ptr + (tzh.charcnt); wall_indicator_ptr = leapinfo_ptr + (tzh.leapcnt*field_size*2); local_indicator_ptr = wall_indicator_ptr + tzh.ttisstdcnt; if (field_size == TZIF2_FIELD_SIZE) { char *start_line_ptr; start_line_ptr = strchr( local_indicator_ptr + tzh.ttisgmtcnt, 10 ); if (start_line_ptr == NULL) printf("nno 'general rule' information found at end of filen"); else { char *end_line_ptr; end_line_ptr = strchr( start_line_ptr+1, 10 ); if (end_line_ptr == NULL) printf("nerror finding 'general rule' info terminator symboln"); else { *end_line_ptr = ' '; memcpy( tz, start_line_ptr+1, end_line_ptr - start_line_ptr ); } } } } #define TZ_DIR_LIST "/usr/share/zoneinfo" int GetTZValFromZoneinfo(const char *zoneInfo, char *TZ ) { int ret = 0; FILE *tz_file; char *tzif_buffer_ptr; char *start_ptr; int field_size; struct stat file_status; timezonefileheader tzh; do{ char zoneInfoPath[128]; snprintf( zoneInfoPath, sizeof(zoneInfoPath),"%s/%s", TZ_DIR_LIST, zoneInfo ); tz_file = fopen( zoneInfoPath, "rb"); if (tz_file == NULL) { error(errno,0,"tz file %s not foundn", zoneInfoPath); ret = -1; break; } if (fstat( fileno( tz_file), &file_status) != 0) { printf("error retreiving file statusn"); ret = -1; break; } tzif_buffer_ptr = (char *) malloc( file_status.st_size ); if (tzif_buffer_ptr == NULL) { printf("memory allocation error - tzif buffern"); ret = errno; break; } if ( fread( tzif_buffer_ptr, file_status.st_size, 1, tz_file) != 1 ) { printf("error reading into tzif buffern"); free(tzif_buffer_ptr); ret = errno; break; } fclose(tz_file); if ( read_tz_header( &tzh, tzif_buffer_ptr ) == FALSE ) { printf("Error reading header file version 1n"); ret = -1; break; } if (tzh.magicnumber[4] == 50 ) { start_ptr = tzif2_handle( &tzh, &tzif_buffer_ptr[HEADER_LEN], file_status.st_size - HEADER_LEN); field_size = TZIF2_FIELD_SIZE; } else { start_ptr = &tzif_buffer_ptr[HEADER_LEN]; field_size = TZIF1_FIELD_SIZE; } if (start_ptr != NULL ) handle_tzfile_data( TZ, tzh, start_ptr, field_size ); free(tzif_buffer_ptr); }while(0); return ret; } void main( int argc, const char *argv[] ) { char tz[128]; memset( tz, 0, sizeof(tz) ); GetTZValFromZoneinfo( argv[1], tz ); printf("tz = %sn", tz ); }
编译执行:
$ gcc tzif-display.c $ ./a.out Cuba tz = CST5CDT,M3.2.0/0,M11.1.0/1
如上就可以提取Cuba的环境变量为CST5CDT,M3.2.0/0,M11.1.0/1,根据需要提取对应的城市地区的环境变量



