linux的时间是msk,linux时区的几个代码片段

这两天学习了Linux环境下的时区方面的东西。做一些小笔记,也包括代码方面。

一、时区名称

从查阅到的资料看,如果没有使用夏令时的话,时区名称形式为“stdoffset”,即时区名加上时间偏移,时间偏移为正数表示西几区,负数表示东几区。如我们国家使用“CST-8”,即东八区。Linux目录/usr/share/zoneinfo/存储着不同的国家/地区的时区信息文件。一般嵌入式设备如果空间有限,可以精简掉部分信息,比如统一使用目录/usr/share/zoneinfo/Etc/下的文件。注意,这个目录的文件都是GMT**形式。东八区为GMT-8,而不是常识中认为的GMT+8,因为GMT+8一般理解为GMT时间加上8小时。但如果设置时区为GMT+8,系统时间与实际时间就会相差16个小时。

二、代码片段

1、获取时区:

一种实现方法是使用date +%z获取时区偏移值,单位为小时,有正负数之分。这个值是正常认知,即正数表示实际时间比GMT多多少个小时。使用date +%Z可获取时区名称。

代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36// 获取时区

int get_timezone(int* timezone)

{

const char* date_cmd = "date +%z";

FILE *fp = NULL;

char timezone_info[16] = {0};

int tmp_time_zone = 0;

fp = popen(date_cmd, "r");

if (fp == NULL)

{

return -1;

}

fread(timezone_info, sizeof(timezone_info), 1, fp);

pclose(fp);

timezone_info[strlen(timezone_info) - 1] = '\0';

if (isdigit(timezone_info[1]) && isdigit(timezone_info[2]))

{

tmp_time_zone = (timezone_info[1] - '0') * 10 + (timezone_info[2] - '0');

if (timezone_info[0] == '-')

{

tmp_time_zone = - tmp_time_zone;

}

*timezone = tmp_time_zone;

return 0;

}

else

{

*timezone = 0;

return -1;

}

return 0;

}

另一种方式是使用timezone这个全局变量,这个变量存储的时间单位为秒,正负数同上第一节分析时区名称含义相同。负数表示东几区。

实现代码如下:

1

2

3

4

5

6

7

8int get_timezone(int* timezone)

{

extern long timezone; // 时区,单位为秒,如GMT-8,为-28800秒

tzset(); // 必须执行

*tz = -(int)(timezone / 3600); // 注意这里的负号

return 0;

}

函数get_timezone返回的值的正负数经过转换后,方便程序计算。比如ONVIF设置的时间只有UTC而不是当地时间,所以将UTC时间加上这个函数返回的时区值即可算出当地时间。除了timezone外,还有tzname和daylight这两个全局变量。它们的使用示例代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31/**

* @brief 获取时区名称、时间偏移值

*

* @param tz1[OUT] 时间名称0

* @param tz2[OUT] 时间名称1

* @param tz_seconds[OUT] 时间偏移值,单位为秒,如东八区,与GMT时间相差-28800秒

* @param daylight_saving[OUT] 夏令时 为0不使用,非0则使用

*

* @return 0: 成功 -1:失败

* @note 使用东八区测试,daylight_saving为1,不知是否正常

测试:

PST8PDT时区

rm /etc/localtime

ln -s /usr/share/zoneinfo/PST8PDT /etc/localtime

tzname[0]:PST

tzname[1]: PDT

timezone: 28800 (正数表示西几区)

*/

void get_tz_name(char* tz1, char* tz2, long* tz_seconds, int* daylight_saving)

{

extern char *tzname[2];

extern long timezone; // 时区,单位为秒,如-8区,为-28800秒

extern int daylight;

tzset(); // 必须执行

strcpy(tz1, tzname[0]);

strcpy(tz2, tzname[1]);

*tz_seconds = timezone;

*daylight_saving = daylight;

}

2、时区名称和时区值转换:

ONVIF使用的时区名称是posix标准,但要从中知道是哪一个时区,以便对应于GMT**的形式。转换代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131/**

* @brief 时区名称转换为时区数值

*

* @param tzname[IN] 时区名称,posix标准,如东八区时区为GMT-8,西八区为GMT+8,西八区也可以用PST8PDT表示

*

* @return -12~12: 成功 1024:失败

* @note 这里返回的时区数值是为了程序方便计算,比如返回8表示是东八区时间(与上述的时区名称不同),

* 这样在GMT时间加上8小时就是当地时间,其它同理

*/

int convert_tzname2tz(const char* tzname)

{

#define IS_TZ(foo) (!strncmp(tzname, foo, strlen(foo)))

// "GMTxxx" first: GMT0/GMT+0/GMT-0 GMT-8 GMT-08

// CST

if (IS_TZ("GMT") || IS_TZ("CST"))

{

char *endptr;

long val = strtol(&tzname[3], &endptr, 10);

if (val >= -12 && val <= 12) return -val;

else return 1024;

}

else if (IS_TZ("IDLW"))

{

return -12;

}

else if (IS_TZ("NT")||IS_TZ("NUT")||IS_TZ("SST"))

{

return -11;

}

else if (IS_TZ("AHST") || IS_TZ("CAT")||IS_TZ("HST")||IS_TZ("HDT")||IS_TZ("TAHT"))

{

return -10;

}

else if (IS_TZ("YST")||IS_TZ("YDT")||IS_TZ("GAMT"))

{

return -9;

}

else if (IS_TZ("PST")||IS_TZ("PDT"))

{

return -8;

}

else if (IS_TZ("MST")||IS_TZ("MDT"))

{

return -7;

}

else if (IS_TZ("CDT"))

{

return -6;

}

else if (IS_TZ("EST")||IS_TZ("EDT")||IS_TZ("EAST"))

{

return -5;

}

else if (IS_TZ("AST")||IS_TZ("ADT")||IS_TZ("GYT")||IS_TZ("WART"))

{

return -4;

}

else if (IS_TZ("CLT")||IS_TZ("BRT")||IS_TZ("PMST")||IS_TZ("WGT"))

{

return -3;

}

else if (IS_TZ("AT")||IS_TZ("GST"))

{

return -2;

}

else if (IS_TZ("WAT"))

{

return -1;

}

else if (IS_TZ("Zulu")||IS_TZ("UT")||IS_TZ("UTC")||IS_TZ("UCT")|| IS_TZ("Greenwich")||IS_TZ("BST"))

{

return 0;

}

else if (IS_TZ("CET")||IS_TZ("FWT")||IS_TZ("MET")||IS_TZ("MEWT")

||IS_TZ("SWT")||IS_TZ("MEST")||IS_TZ("MESZ")||IS_TZ("SST")

||IS_TZ("FST"))

{

return 1;

}

else if (IS_TZ("EET")||IS_TZ("IST"))

{

return 2;

}

else if (IS_TZ("BT")||IS_TZ("MSK"))

{

return 3;

}

else if (IS_TZ("ZP4"))

{

return 4;

}

else if (IS_TZ("ZP5"))

{

return 5;

}

else if (IS_TZ("ZP6"))

{

return 6;

}

else if (IS_TZ("ZP7"))

{

return 7;

}

else if (IS_TZ("WAST")||IS_TZ("HKT")||IS_TZ("SGT"))

{

return 8;

}

else if (IS_TZ("JST"))

{

return 9;

}

else if (IS_TZ("ACT"))

{

return 10;

}

else if (IS_TZ("EAST"))

{

return 11;

}

else if (IS_TZ("IDLE"))

{

return 12;

}

else

{

return 1024;

}

return 1024;

}

从时区数值转换为时区名称代码示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45/*

g_tz_name是时区名称,请到 /usr/share/zoneinfo/Etc/目录查看文件。

数值前面正数表示时区位于本初子午线之西,负数表示时区位于本初子午线之东。

如不明白,请在linux环境执行命令“man tzset”阅读文档。

*/

const char* g_tz_name[25] = {

"GMT+12",

"GMT+11",

"GMT+10",

"GMT+9",

"GMT+8",

"GMT+7",

"GMT+6",

"GMT+5",

"GMT+4",

"GMT+3",

"GMT+2",

"GMT+1",

"GMT",

"GMT-1",

"GMT-2",

"GMT-3",

"GMT-4",

"GMT-5",

"GMT-6",

"GMT-7",

"GMT-8",

"GMT-9",

"GMT-10",

"GMT-11",

"GMT-12",

};

/**

* @brief 返回时区名称

*

* @param timezone[IN] 时区数值,如东八区为+8,西八区为-8

*

* @return 时区名称

*/

const char* get_timezone_info(int timezone)

{

return g_tz_name[timezone + 12];

}

李迟 2016.01.23 周六 今天特冷

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值