C语言程序对夏令时的处理

C语言程序对夏令时的处理,第1张

背景

在设备应用中,用户需要根据自己的时区设置设备时区。在可交互的系统中或者完整的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"

/**
 * @brief 根据设置的地区设置时区
 * */
int setTimeZone( const char *pRegion )
{
  int ret = 0;

  for( int i=0; i<sizeof(cityList)/2/128; i++ ){
    /* printf("--->%s,%d,%s\n", pRegion, i, cityList[i][0]); */
    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:%02d\n", 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("\n\n");

  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

/***************************************************
* definition of a tzfile header
***************************************************/
#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#
defineTZIF1_FIELD_SIZE 4 #
defineTZIF2_FIELD_SIZE 8 /***************************************************
* parse a tzfile "long format" value
***************************************************/


long
parse_tz_long (const char * ,sourceptrconst int ) field_sizelong
{
	= retval 0 ;char
	* ;long_ptr//	if (sizeof(long) < field_size)

//		printf("warning: field truncated because it is larger than a 'long' integer\n\n");
int

	, i;j=
	long_ptr ( char*)& ;retvalif
	( (<field_size sizeof (long))&& ( [sourceptr0]8 >> ))for
	{
		( =isizeof(long)-1;( )i>=field_size;-- i)[ long_ptr]i= 255 ;} 
	=
	j 0 ;for
	( =i-field_size1;( 0i>=)&& ( <jsizeof(long));-- i)[
	{
		long_ptr]j= [ sourceptr]i;++
		j;}
	return
	; retval}
/***************************************************
* read a tzheader file
***************************************************/

int
read_tz_header (* timezonefileheader ,headerconst  char * )temp_bufferconst
{
	int = field_size 4 ;memcpy

	(, header->magicnumber& [temp_buffer0],5 ) ;[
	header->magicnumber5]= ';' =parse_tz_long

	header->ttisgmtcnt ( &[20temp_buffer],); field_size=parse_tz_long
	header->ttisstdcnt ( &[24temp_buffer],); field_size=parse_tz_long
	header->leapcnt ( &[28temp_buffer],); field_size=parse_tz_long
	header->timecnt ( &[32temp_buffer],); field_size=parse_tz_long
	header->typecnt ( &[36temp_buffer],); field_size=parse_tz_long
	header->charcnt ( &[40temp_buffer],); field_sizeif(

	== 0header->typecnt ) printf(
	{
		"Error in file format. Zero local time types suggested.\n");return;
		} FALSEif
	(

	== 0header->timecnt ) printf(
	{
		"No transition times recorded in this file\n");return;
		} FALSEreturn
	;

} TRUE/***********************************************************************
* tzif2_handle
***********************************************************************/
char

*
tzif2_handle( *, timezonefileheader consttzhchar * , size_ttzfile_buffer_ptr) char buffer_size *
{
	; charstart_ptr[
	5 magicnumber]="TZif2" ; =memmem

	start_ptr ( ,, tzfile_buffer_ptr& buffer_size, 5magicnumber) ; if(
	== NULLstart_ptr ) printf(
	{
		"error finding tzif2 header\n");returnNULL
		; }if
	(

	read_tz_header ( ,( tzhchar *))== start_ptr ) printf FALSE (
	{
		"Error reading header file version 2\n");returnNULL
		; }return
	+

	; start_ptr } HEADER_LEN/***************************************************
* Display contents of a timezone file
***************************************************/
void


handle_tzfile_data
( char*	, consttz,
                            const timezonefileheader tzhchar
							* ,const tzfile_buffer_ptrint
							/// 4bytes for tzif1, 8bytes for tzif2 ) field_size /***************************************************
	 * 
	 * Structure of the timezone files
	 * 
	 ***************************************************/
							char
{

	 *
		; charlocal_time_type_ptr*

		; charttinfo_read_ptr*
		;char tz_abbrev_ptr*
		; charleapinfo_ptr*
		; charwall_indicator_ptr*
		; /********************************************************************
 * 
 * Beginning of code for function display_tzfile_data
 * 
 ********************************************************************/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 . *tzh6typecnt ) ;=+

	leapinfo_ptr ( tz_abbrev_ptr . )tzh;charcnt=+


	wall_indicator_ptr ( leapinfo_ptr . *tzh*leapcnt2field_size);=+


	local_indicator_ptr . wall_indicator_ptr ; tzhifttisstdcnt(

	== )field_size char TZIF2_FIELD_SIZE*
	{
		; =start_line_ptrstrchr
		start_line_ptr ( +. local_indicator_ptr , tzh10ttisgmtcnt) ; if(
		== NULLstart_line_ptr ) printf(
			"\nno \'general rule\' information found at end of file\n");elsechar
		*
		{
			; =end_line_ptrstrchr
			end_line_ptr ( +1 start_line_ptr,10) ; if(
			== NULLend_line_ptr ) printf(
				"\nerror finding \'general rule\' info terminator symbol\n");else*
			=
			{
				';'end_line_ptr /* printf("\ngeneral rule (unparsed): %s\n", start_line_ptr+1 ); */ memcpy(
				,
                +1 tz, start_line_ptr-); end_line_ptr } start_line_ptr }}
			}
			
		#
			
	define

TZ_DIR_LIST

"/usr/share/zoneinfo"int GetTZValFromZoneinfo (
const char*, char *zoneInfo) int =TZ 0
{
    ; ret * ;char
	FILE *tz_file;
	char *tzif_buffer_ptr;
	int ;start_ptrstruct
	stat   field_size;
	; do file_statuschar
	timezonefileheader tzh[

    128{
        ] zoneInfoPath;snprintf(,
        sizeof( zoneInfoPath) ,"%s/%s"zoneInfoPath,,); TZ_DIR_LIST= zoneInfo fopen(

        tz_file , "rb") zoneInfoPath; if(==

        NULL )tz_file error (,
        {
            0,errno"tz file %s not found\n",);= zoneInfoPath-1
            ret ; break;}
            if(
        fstat

        ( fileno() ,& tz_file)!= 0file_status) printf ("error retreiving file status\n"
        {
            );=-1
            ret ; break;}
            =(
        char

        tzif_buffer_ptr * )malloc (. ); file_statusifst_size (==
        NULL )tzif_buffer_ptr printf ("memory allocation error - tzif buffer\n"
        {
            );=;break
            ret ; errno}
            if(
        fread

        ( , ., tzif_buffer_ptr1 file_status,st_size) !=1 tz_file) printf ( "error reading into tzif buffer\n"
        {
            );free()
            ;=tzif_buffer_ptr;break
            ret ; errno}
            fclose(
        )
        ;iftz_file(read_tz_header


        ( & ,) ==tzh) tzif_buffer_ptr printf ( FALSE "Error reading header file version 1\n"
        {
            );=-1
            ret ; break;}
            if(
        .

        [ 4tzh]magicnumber==50) = tzif2_handle (
        {
            start_ptr & ,& [tzh] ,tzif_buffer_ptr.HEADER_LEN-) file_status;st_size = HEADER_LEN;}
            field_size else TZIF2_FIELD_SIZE=
        &
        [
        {
            start_ptr ] ;tzif_buffer_ptr=HEADER_LEN;}
            field_size if TZIF1_FIELD_SIZE(
        !=
        NULL )start_ptr handle_tzfile_data ( , ,, TZ) tzh; start_ptrfree field_size ()

        ;}tzif_buffer_ptrwhile(
    0);return;}


    void retmain
(

int ,const char argc* [ ] )argvchar[ 128
{
    ] tz;/* GetTZValFromZoneinfo( "America/New_York", tz ); */memset(
    ,
    0, tzsizeof () );tzGetTZValFromZoneinfo ([
    1] argv,);printf tz ("tz = %s\n"
    ,);} tz =Cuba
CST5CDT,M3.2.0/0,M11.1.0/1

编译执行:

$ gcc tzif-display.c
$ ./a.out Cuba
tz  CST5CDT,M3.2.0/0,M11.1.0/1

如上就可以提取的环境变量为,根据需要提取对应的城市地区的环境变量

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/755950.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-30
下一篇 2022-04-30

发表评论

登录后才能评论

评论列表(0条)

保存