2016-01-04 11:07:01 elitah 阅读数 647

需要注意的:

  • time函数,可以传入time_t类型的指针,如果为NULL,那么返回的值是函数内部的缓冲去
  • localtime函数返回的指针也是函数内部缓冲区的地址,重复调用,那么最后一次传入的参数将被转换

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <time.h>

int main(int argc, char **argv)
{
	struct tm *local_start = NULL, *local_stop = NULL;

	time_t now1 = 0, now2 = 0;
	
	now1 = time(NULL);
	
	sleep(3);

	now2 = time(NULL);
	
	printf("%lu, %lu\n", now1, now2);
	
	local_start = localtime(&now1);

	printf("%d-%d-%d %d:%d:%d\n", local_start->tm_year + 1900, local_start->tm_mon + 1, local_start->tm_mday, local_start->tm_hour, local_start->tm_min, local_start->tm_sec);

	local_stop = localtime(&now2);
	
	printf("%d-%d-%d %d:%d:%d\n", local_stop->tm_year + 1900, local_stop->tm_mon + 1, local_stop->tm_mday, local_stop->tm_hour, local_stop->tm_min, local_stop->tm_sec);

	return 0;
}

2019-01-16 12:39:02 u010025966 阅读数 1786

1.select from_unixtime(unix_timestamp(),‘yyyy/MM/dd HH:mm:ss’);
执行时间与本地时间有误差
时间戳:2019/01/16 02:36:13
本地时:2019-01-16 10:36:10
正好相差8小时
安装ntp服务同步时间也无效最后翻找官方文档查看unix_timestamp获取时间属性:
Converts time string in format yyyy-MM-dd HH:mm:ss to Unix timestamp (in seconds), using the default timezone and the default locale, return 0 if fail;
翻译:
将时间字符串转换为Unix时间戳(以秒为单位),使用默认时区和默认语言环境,如果失败,返回0

2.在得知时由默认语言环境获取的时间所以想到

timedatectl 

在服务器上执行

# timedatectl 
      Local time: Wed 2019-01-16 10:36:10 CST
  Universal time: Wed 2019-01-16 02:36:10 UTC
        RTC time: Wed 2019-01-16 02:36:10
       Time zone: Asia/Shanghai (CST, +0800)
     NTP enabled: yes
NTP synchronized: yes
 RTC in local TZ: yes
      DST active: n/a

Warning: The system is configured to read the RTC time in the local time zone.
         This mode can not be fully supported. It will create various problems
         with time zone changes and daylight saving time adjustments. The RTC
         time is never updated, it relies on external facilities to maintain it.
         If at all possible, use RTC in UTC by calling
         'timedatectl set-local-rtc 0'.

刚好差了8小时
查找了资料也不知道怎么修改

2017-01-18 11:43:00 mill_li 阅读数 10776

我们平常说时间都说的几点几分几秒,星期几,但是在计算机里面并不是直接使用我们所说的时间,而是使用Unix时间戳,这样不管是哪个平台,哪个系统,都可以根据自己对时间的定义进行转换,像Java,PHP等都提供了接口来进行转化,C库里面也有这样的函数,那具体是怎么实现的呢?要了解这个问题首先我们就必须要清楚什么是Unix时间戳,什么是我们平常使用的时间。

1. Unix时间戳

UNIX时间戳:Unix时间戳(英文为Unix epoch, Unix time, POSIX time 或 Unix timestamp)
是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。
UNIX时间戳的0按照ISO 8601规范为 :1970-01-01T00:00:00Z.
一个小时表示为UNIX时间戳格式为:3600秒;一天表示为UNIX时间戳为86400秒,闰秒不计算。
在大多数的UNIX系统中UNIX时间戳存储为32位,这样会引发2038年问题或Y2038。

对应的时间和秒数如下

时间
1 分钟 60 秒
1 小时 3600 秒
1 天 86400 秒
1 周 604800 秒
1 月 (30.44 天) 2629743 秒
1 年 (365.24 天) 31556926 秒

2. 本地时间

平常我们最常听见的是阴历和阳历之分,阴历是按照月亮的运行规律来计算日期的,那我们所说的阳历又是什么呢?其实阳历或者说叫西历最早是叫做儒略历,是由罗马共和国独裁官儒略·恺撒(即盖乌斯·尤里乌斯·凯撒)采纳数学家兼天文学家索西琴尼的计算后,于公元前45年1月1日起执行的取代旧罗马历法的一种历法,但令人遗憾的是,当时那些颁发历书的祭司们,却不了解改历的实质。结果,可笑的是,当时罗马执掌颁布历书的祭司竟把原来历法上规定的“每隔三年置闰”误解为“每三年置一闰”。从公元前45年起,到公元前9年为止,这之间本应设置10个闰年,他们却设置了13个闰年。公元前9年,人们终于发现这一差错,这时恺撒的外甥奥古斯都执掌政权,他纠正了这个错误,才停止了“三年一闰”。奥古斯都下令改正过来,改到次年(公元前8年)才置闰年。当改正这种闰年的错误时已经多闰了3年,为了去掉着多闰的3年,奥古斯都又下令停闰3年,即以公元前5年、公元前1年、公元前4年仍为平年,以后恢复了每4年一闰的规定了。奥古斯都为了宣扬这一功劳,仿效儒略·恺撒的做法,下令把自己出生的儒略历中的8月改称为奥古斯都月(这一名称在西方沿用到今天)。8月后的大,小月份都翻转过来了,9月为30天,10月为31天,11月为30天,12月为31天,这种置月方式一直沿用至今。如此一来,一年多出了一天,于是也从二月份29天里再减去一天,二月份只剩下28天了 1582年罗马教皇格里高利对”儒略历”又进行修改,规定被4整除的年为闰年,但逢百之年只有能被400除尽才能是闰年。这就是使用至今的“格里历”。这样做是为了使历年与回归年相接近。回归年的周期是365.2425天。儒略历一年的平均长度为365.25日,比回归年(365.2425天)长11分14秒,自公元325年(该年采用儒略历作为宗教日历)积累到十六世纪末,春分日由3月21日提早到3月11日。于是罗马教皇格里高利十三世(Gregorius XⅢ)于1582年10月4日还下令将次日(即原10月5日)定为10月15日,把春分日又恢复为3月21日。这样,1582年的10月5日-14日这十天就成了“不存在”的日子,变为历史的空白。1949年9月27日,经过中国人民政治协商会议第一届全体会议通过,中华人民共和国使用国际社会多数国家通用的西历和西元作为历法和纪年。

3. 蔡勒公式

清楚了Unix时间戳和公历的意义,怎么讲秒数转化成本地时间大家心里应该有个大概了,既然本地时间知道了,那我们可不可以根据这个日期直接知道那一天是星期几呢?数学家蔡勒(Zeller)推算出了这个公式,大家称为蔡勒公式,使用这个公式随便给出一个日期,就可以计算出是星期几。

公式具体是这样的
W = [C / 4] - 2C + y + [y / 4] + [13 * (M + 1) / 5] + d - 1
或者是:w = y + [y / 4] + [c / 4] - 2c + [26(m + 1) / 10] + d - 1

公式中的符号含义如下:
w:星期; w对7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六
c:世纪-1(前两位数)
y:年(后两位数)
m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算)
d:日 [ ]代表取整,即只要整数部分。

下面以中华人民共和国成立100周年纪念日那天(2049年10月1日)来计算是星期几,过程如下:
w = y + [y / 4] + [c / 4] - 2c + [26(m + 1) / 10] + d - 1
= 49 + [49 / 4] + [20 / 4] - 2 × 20 + [26 × (10 + 1) / 10] + 1 - 1
= 49 + [12.25] + 5 - 40 + [28.6]
= 49 + 12 + 5 - 40 + 28
= 54 (除以7余5)
即2049年10月1日(100周年国庆)是星期五。

再比如计算2006年4月4日,过程如下:
w = y + [y / 4] + [c / 4] - 2c + [26(m + 1) / 10] + d - 1
= 6 + [6 / 4] + [20 / 4] - 2 * 20 + [26 * (4 + 1) / 10] + 4 - 1
= -12 (除以7余5,注意对负数的取模运算!实际上应该是星期二而不是星期五)

不过要注意的是,蔡勒公式只适合于1582年(明朝万历十年)10月15日之后的情形。

4. 具体实现

清楚了上面这些内容,我们来看一下用C怎么实现Unix时间戳和本地时间的相互转化,并根据指定的时间算出对应的日期

#include <stdio.h>
#include <stdbool.h>

#define UTC_BASE_YEAR 1970
#define MONTH_PER_YEAR 12
#define DAY_PER_YEAR 365
#define SEC_PER_DAY 86400
#define SEC_PER_HOUR 3600
#define SEC_PER_MIN 60

/* 每个月的天数 */
const unsigned char g_day_per_mon[MONTH_PER_YEAR] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

/* 自定义的时间结构体 */
typedef struct
{
    unsigned short nYear;
    unsigned char nMonth;
    unsigned char nDay;
    unsigned char nHour;
    unsigned char nMin;
    unsigned char nSec;
    unsigned char DayIndex; /* 0 = Sunday */
} mytime_struct;

/*
 * 功能:
 *     判断是否是闰年
 * 参数:
 *     year:需要判断的年份数
 *
 * 返回值:
 *     闰年返回1,否则返回0
 */
unsigned char applib_dt_is_leap_year(unsigned short year)
{
    /*----------------------------------------------------------------*/
    /* Local Variables                                                */
    /*----------------------------------------------------------------*/

    /*----------------------------------------------------------------*/
    /* Code Body                                                      */
    /*----------------------------------------------------------------*/
    if ((year % 400) == 0) {
        return 1;
    } else if ((year % 100) == 0) {
        return 0;
    } else if ((year % 4) == 0) {
        return 1;
    } else {
        return 0;
    }
}

/*
 * 功能:
 *     得到每个月有多少天
 * 参数:
 *     month:需要得到天数的月份数
 *     year:该月所对应的年份数
 *
 * 返回值:
 *     该月有多少天
 *
 */
unsigned char applib_dt_last_day_of_mon(unsigned char month, unsigned short year)
{
    /*----------------------------------------------------------------*/
    /* Local Variables                                                */
    /*----------------------------------------------------------------*/

    /*----------------------------------------------------------------*/
    /* Code Body                                                      */
    /*----------------------------------------------------------------*/
    if ((month == 0) || (month > 12)) {
        return g_day_per_mon[1] + applib_dt_is_leap_year(year);
    }

    if (month != 2) {
        return g_day_per_mon[month - 1];
    } else {
        return g_day_per_mon[1] + applib_dt_is_leap_year(year);
    }
}

/*
 * 功能:
 *     根据给定的日期得到对应的星期
 * 参数:
 *     year:给定的年份
 *     month:给定的月份
 *     day:给定的天数
 *
 * 返回值:
 *     对应的星期数,0 - 星期天 ... 6 - 星期六
 */
unsigned char applib_dt_dayindex(unsigned short year, unsigned char month, unsigned char day)
{
    char century_code, year_code, month_code, day_code;
    int week = 0;

    century_code = year_code = month_code = day_code = 0;

    if (month == 1 || month == 2) {
        century_code = (year - 1) / 100;
        year_code = (year - 1) % 100;
        month_code = month + 12;
        day_code = day;
    } else {
        century_code = year / 100;
        year_code = year % 100;
        month_code = month;
        day_code = day;
    }

    /* 根据蔡勒公式计算星期 */
    week = year_code + year_code / 4 + century_code / 4 - 2 * century_code + 26 * ( month_code + 1 ) / 10 + day_code - 1;
    week = week > 0 ? (week % 7) : ((week % 7) + 7);

    return week;
}

/*
 * 功能:
 *     根据UTC时间戳得到对应的日期
 * 参数:
 *     utc_sec:给定的UTC时间戳
 *     result:计算出的结果
 *     daylightSaving:是否是夏令时
 *
 * 返回值:
 *     无
 */
void utc_sec_2_mytime(unsigned int utc_sec, mytime_struct *result, bool daylightSaving)
{
    /*----------------------------------------------------------------*/
    /* Local Variables                                                */
    /*----------------------------------------------------------------*/
    int sec, day;
    unsigned short y;
    unsigned char m;
    unsigned short d;
    unsigned char dst;

    /*----------------------------------------------------------------*/
    /* Code Body                                                      */
    /*----------------------------------------------------------------*/

    if (daylightSaving) {
        utc_sec += SEC_PER_HOUR;
    }

    /* hour, min, sec */
    /* hour */
    sec = utc_sec % SEC_PER_DAY;
    result->nHour = sec / SEC_PER_HOUR;

    /* min */
    sec %= SEC_PER_HOUR;
    result->nMin = sec / SEC_PER_MIN;

    /* sec */
    result->nSec = sec % SEC_PER_MIN;

    /* year, month, day */
    /* year */
    /* year */
    day = utc_sec / SEC_PER_DAY;
    for (y = UTC_BASE_YEAR; day > 0; y++) {
        d = (DAY_PER_YEAR + applib_dt_is_leap_year(y));
        if (day >= d)
        {
            day -= d;
        }
        else
        {
            break;
        }
    }

    result->nYear = y;

    for (m = 1; m < MONTH_PER_YEAR; m++) {
        d = applib_dt_last_day_of_mon(m, y);
        if (day >= d) {
            day -= d;
        } else {
            break;
        }
    }

    result->nMonth = m;
    result->nDay = (unsigned char) (day + 1);
    /* 根据给定的日期得到对应的星期 */
    result->DayIndex = applib_dt_dayindex(result->nYear, result->nMonth, result->nDay);
}

/*
 * 功能:
 *     根据时间计算出UTC时间戳
 * 参数:
 *     currTime:给定的时间
 *     daylightSaving:是否是夏令时
 *
 * 返回值:
 *     UTC时间戳
 */
unsigned int mytime_2_utc_sec(mytime_struct *currTime, bool daylightSaving)
{
    /*----------------------------------------------------------------*/
    /* Local Variables                                                */
    /*----------------------------------------------------------------*/
    unsigned short i;
    unsigned int no_of_days = 0;
    int utc_time;
    unsigned char dst;

    /*----------------------------------------------------------------*/
    /* Code Body                                                      */
    /*----------------------------------------------------------------*/
    if (currTime->nYear < UTC_BASE_YEAR) {
        return 0;
    }

    /* year */
    for (i = UTC_BASE_YEAR; i < currTime->nYear; i++) {
        no_of_days += (DAY_PER_YEAR + applib_dt_is_leap_year(i));
    }

    /* month */
    for (i = 1; i < currTime->nMonth; i++) {
        no_of_days += applib_dt_last_day_of_mon((unsigned char) i, currTime->nYear);
    }

    /* day */
    no_of_days += (currTime->nDay - 1);

    /* sec */
    utc_time = (unsigned int) no_of_days * SEC_PER_DAY + (unsigned int) (currTime->nHour * SEC_PER_HOUR +
                                                                currTime->nMin * SEC_PER_MIN + currTime->nSec);

    if (dst && daylightSaving) {
        utc_time -= SEC_PER_HOUR;
    }

    return utc_time;
}

int main(int argc, char *argv[])
{
    mytime_struct my_time;
    unsigned int sec;
    char *DayIndex[] = {"Sun.", "Mon.", "Tues.", "Wed.", "Thur.", "Fri.", "Sat."};

    /* 这里根据UTC时间戳计算出来的时间是零时区的时间,所以如果要转化成北京时间就需要多加8小时 */
    utc_sec_2_mytime(1484537668 + 8 * SEC_PER_HOUR, &my_time, false);


    printf("%d-%d-%d %d:%d:%d %s\n", my_time.nYear, my_time.nMonth, my_time.nDay,
            my_time.nHour, my_time.nMin, my_time.nSec, DayIndex[my_time.DayIndex]);

    sec = mytime_2_utc_sec(&my_time, false);
    printf("sec = %d\n", sec);

    return 0;
}

基本上的内容就这些了,平常最好能够直接使用系统提供的接口,如果不能使用的话就自己实现,根据上面的代码修改成自己需要的,如果有不对的地方,希望能够批评指正

参考文献
http://blog.csdn.net/areskris/article/details/8661983

2018-04-11 10:32:37 oshan2012 阅读数 1921
//时间测试,将unix timestamp 和本地时间进行转换
//0x5a603bfe   北京时间 2018/1/18 14:17:34
/* 下面打印是的格林威治标准时间
年:118 
月:0 
日:18 
时:6 
分:17 
秒:34

格林威治标准时间比北京时间晚8个小时
*/
void time_test(void)
{
	//将unix timestamp 转为本地时间
	struct tm *gm_date;
	time_t seconds=0x5a603bfe;//unix timestamp
	gm_date = localtime(&seconds);
	printf("年:%d \r\n",gm_date->tm_year);
	printf("月:%d \r\n",gm_date->tm_mon);
	printf("日:%d \r\n",gm_date->tm_mday);
	printf("时:%d \r\n",gm_date->tm_hour);
	printf("分:%d \r\n",gm_date->tm_min);
	printf("秒:%d \r\n",gm_date->tm_sec);
	
	//将本地时间转为unix timestamp 
	gm_date->tm_year=118;//2018年,+1900就是现在的年
	gm_date->tm_mon=3;//4月
	gm_date->tm_mday=11;
	gm_date->tm_hour=10;
	gm_date->tm_min=8;
	gm_date->tm_sec=30;
	
	seconds=mktime(gm_date);
	printf("unix timestamp:%08x \r\n",seconds);
	//unix timestamp:5acdde9e 
	//北京时间:	2018/4/11 18:8:30
	
}

2017-05-09 00:14:11 xi_gua_gua 阅读数 2694
Unix时间戳(Unix timestamp),或称Unix时间(Unix time)POSIX时间(POSIX time),是一种时间表示方式,定义为从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数。Unix时间戳不仅被使用在Unix 系统、类Unix系统中,也在许多其他操作系统中被广告采用。

【注意】目前相当一部分操作系统使用32位二进制数字表示时间。此类系统的Unix时间戳最多可以使用到格林威治时间2038年01月19日03时14分07秒(二进制:01111111 11111111 11111111 11111111)。其后一秒,二进制数字会变为10000000 00000000 00000000 00000000,发生溢出错误,造成系统将时间误解为1901年12月13日20时45分52秒。这很可能会引起软件故障,甚至是系统瘫痪。使用64位二进制数字表示时间的系统(最多可以使用到格林威治时间292,277,026,596年12月04日15时30分08秒)则基本不会遇到这类溢出问题。

目前经常出现的时间有三个:
本地时间(locale time)
格林威治时间(Greenwich Mean Time GMT
时间协调时间 (Universal Time Coordinated UTC
 
时间标准:
(1)世界时 
世界时是最早的时间标准。在1884年,国际上将1s确定为全年内每日平均长度的1/8.64×104。以此标准形成的时间系统,称为世界时(UT1)。 1972年国际上开始使用国际原子时标,从那以后,经过格林威治老天文台本初子午线的时间便被称为世界时(UT2),或称格林威治时间GMT),UT2是对地球转速周期性差异进行校正后的世界时。 
(2)原子时 
1967年,人们利用铯原子振荡周期极为规律的特性,研制出了高精度的原子时钟,将铯原子能级跃迁辐射9192631770周所经历的时间定为1s。现在用的时间就是1971年10月定义的国际原子时,是通过世界上大约200多台原子 钟进行对比后,再由国际度量衡局时间所进行数据处理,得出的统一的原子时,简称TAI。 
(3)世界协调时 
世界协调时是以地球自转为基础的时间标准。由于地球自转速度并不均匀,并非每天都是精确的86400原子s,因而导致了自转时间与世界时之间存在18个月有1s的误差。为纠正这种误差,国际地球自转研究所根据地球自转的实际情况对格林威治时间进行增减闰s的调整,与国际度量衡局时间所联合向全世界发布标准时间,这就是所谓的世界协调时(UTC:CoordinatdeUniversalTime)。UTC的表示方式为:年(y)、月(m)、日(d)、时(h)、分(min)、秒(s),均用数字表示。

GPS 系统中有两种时间区分,一为UTC,另一为LT(地方时)两者的区别为时区不同,UTC就是0时区的时间,地方时为本地时间,如北京为早上八点(东八区),UTC时间就为零点,时间比北京时晚八小时,以此计算即可
  通过上面的了解,我们可以认为格林威治时间就是时间协调时间(GMT=UTC),格林威治时间和UTC时间均用秒数来计算的。

   而在我们平时工作当中看到的计算机日志里面写的时间大多数是用UTC时间来计算的,那么我们该怎么将UTC时间转化为本地时间便于查看日志,那么在作程序开发时又该怎么将本地时间转化为UTC时间呢?
   下面就介绍一个简单而使用的工具,就是使用linux/unix命令date来进行本地时间和local时间的转化。
   大家都知道,在计算机中看到的utc时间都是从(1970年01月01日 0:00:00)开始计算秒数的。所看到的UTC时间那就是从1970年这个时间点起到具体时间共有多少秒。
我们在编程中可能会经常用到时间,比如取得系统的时间(获取系统的年、月、日、时、分、秒,星期等),或者是隔一段时间去做某事,那么我们就用到一些时间函数。

linux下存储时间常见的有两种存储方式,(1)从1970年到现在经过了多少秒(2)用一个结构来分别存储年月日时分秒的
(1)time_t 这种类型就是用来存储从1970年到现在经过了多少秒
struct timeval //精确到微妙
{
    long tv_sec; /*秒*/
    long tv_usec; /*微秒*/
};
struct timespec //精确到纳秒
{
time_t tv_sec; //秒
long tv_nsec; //纳秒
}
1s = 1000ms(毫秒) = 1000*1000us(微妙) = 1000*1000*1000ns(纳秒)

(2)直接存储年月日的是一个结构:
struct tm
{
    int tm_sec;  /*秒,正常范围0-59, 但允许至61*/
    int tm_min;  /*分钟,0-59*/
    int tm_hour; /*小时, 0-23*/
    int tm_mday; /*日,即一个月中的第几天,1-31*/
    int tm_mon;  /*月, 从一月算起,0-11*/  1+p->tm_mon;
    int tm_year;  /*年, 从1900至今已经多少年*/  1900+ p->tm_year;
    int tm_wday; /*星期,一周中的第几天, 从星期日算起,0-6*/
    int tm_yday; /*从今年1月1日到目前的天数,范围0-365*/
    int tm_isdst; /*日光节约时间的旗标*/
};
【注意】需要特别注意的是,年份是从1900年起至今多少年,而不是直接存储如2011年;月份从0开始的,0表示一月;星期也是从0开始的,0表示星期日,1表示星期一。

下面介绍一下我们常用的时间函数:
#include <time.h>
(1)将结构中的信息转换为真实世界的时间,以字符串的形式显示
char *asctime(const struct tm* timeptr);

(2)将timep转换为真是世界的时间,以字符串显示,它和asctime不同就在于传入的参数形式不一样
char *ctime(const time_t *timep);

(3)返回两个时间相差的秒数
double difftime(time_t time1, time_t time2);

(4)返回当前距离1970年的秒数和微妙数,后面的tz是时区,一般不用
int gettimeofday(struct timeval *tv, struct timezone *tz);

(5)将time_t表示的时间转换为没有经过时区转换的UTC时间,是一个struct tm结构指针
struct tm* gmtime(const time_t *timep);

(6)和gmtime类似,但是它是经过时区转换的时间。
stuct tm* localtime(const time_t *timep);

(7)将struct tm 结构的时间转换为从1970年至今的秒数
time_t mktime(struct tm* timeptr);

(8)取得从1970年1月1日至今的秒数
time_t time(time_t *t);
没有更多推荐了,返回首页