Problems found during Erlang timestamp conversion

Yesterday, I wrote a timestamp conversion function by hand in the task. During the period, I found that the time converted according to the timestamp did not match the current time. After trying for a long time, I found the problem and the solution.

In fact, the solution is very simple, straight to the point, that is, when the world time is converted to local time to judge the hour, minute and second, the conversion is 8 hours away. When it is found that it is the time difference of Beijing time, manually add calendar:universal_time_to_local_time(DataTime). Although the problem can be solved in one or two lines, that is not the purpose. By the way, I will review the issue of date, time processing and timestamp conversion in Erlang.

Get the current time

There are many ways to get the current time in Erlang, such as erlang:now(), os:timestamp(), etc.,

These are the time from GMT zero to the current time, and what is returned is the tuple {MegaSecs, Secs, MicroSecs} from 1970-1-1 00:00:00 to the current time.

3> erlang:now().
{
    
    1616,730132,577025}
4> erlang:now().
{
    
    1616,730856,937025}
5> os:timestamp().
{
    
    1616,730864,175000}
6> os:timestamp().
{
    
    1616,730871,917000}
7>

The 10-digit timestamp has to be calculated based on this

timestamp() ->
    {
    
    M, S, _} = os:timestamp(),
    M * 1000000 + S.

run

1> test:timestamp().
1616984171
2> 

The timestamp is too advanced, the level is not up to the level, I usually use less or like the year, month, day, hour, minute and second

Get world time

% 本地时间
local_time() ->
    calendar:local_time().

% 世界时间
world_time() ->
    calendar:universal_time().

run

1> calendar:local_time().
{
    
    {
    
    2021,3,29},{
    
    9,47,51}}
2> calendar:universal_time().
{
    
    {
    
    2021,3,29},{
    
    1,47,59}}
3> erlang:timestamp().
{
    
    1616,983999,958998}
4> os:timestamp().
{
    
    1616,984114,372000}
5> 

It can be found that there is a difference of 8 hours between the world standard time and the local time (nonsense, Beijing is in Dongba District +8h),

5> {
    
    {
    
    Year, Month, Day}, {
    
    Hour, Minite, Second}} = calendar:local_time().
{
    
    {
    
    2021,3,29},{
    
    10,25,47}}
6> Year.
2021
7> Hour.
10

Let's make a match

Other functions

Calculate the number of seconds in hours, minutes and seconds

8> calendar:time_to_seconds({
    
    10,25,47}).
37547
9> calendar:time_to_seconds({
    
    23,59,59}).
86399
10> calendar:time_to_seconds({
    
    0,1,0}).
60

Standard conversion of time stamp (10 digits) and year, month, day, hour, minute and second

% 时间转时间戳,格式:{<!-- -->{2021,3,29},{10,25,47}}
datetime_to_timestamp(DateTime) ->
    calendar:datetime_to_gregorian_seconds(DateTime) -
        calendar:datetime_to_gregorian_seconds({
    
    {
    
    1970,1,1}, {
    
    0,0,0}}).


% 时间戳转时间
timestamp_to_datetime(Timestamp) ->
    calendar:gregorian_seconds_to_datetime(Timestamp +
        calendar:datetime_to_gregorian_seconds({
    
    {
    
    1970,1,1}, {
    
    0,0,0}})).

Under the experiment

1> test:datetime_to_timestamp({
    
    {
    
    2021,3,29},{
    
    10,25,47}}).
1617013547
2> test:timestamp_to_datetime(1617013547).
{
    
    {
    
    2021,3,29},{
    
    10,25,47}}
3> test:timestamp_to_datetime(test:timestamp()).
{
    
    {
    
    2021,3,29},{
    
    2,38,33}}

Simple and easy to use, you can find that there is a time difference between the standard time and the actual time. If there is a time zone problem, remember to add a line of this

Improved time zone

% 时间转时间戳,格式:{<!-- -->{2021,3,29},{10,25,47}}
datetime_to_timestamp(DateTime) ->
    calendar:datetime_to_gregorian_seconds(DateTime) -
        calendar:datetime_to_gregorian_seconds({
    
    {
    
    1970,1,1}, {
    
    0,0,0}}).


% 时间戳转时间
timestamp_to_datetime(Timestamp) ->
    DT = calendar:gregorian_seconds_to_datetime(Timestamp +
        calendar:datetime_to_gregorian_seconds({
    
    {
    
    1970,1,1}, {
    
    0,0,0}})),
    calendar:universal_time_to_local_time(DT).

Re-experiment

1> test:timestamp_to_datetime(test:timestamp()).
{
    
    {
    
    2021,3,29},{
    
    10,40,9}}
2> 

Seconds to hours, minutes and seconds

6> calendar:seconds_to_daystime(86000).
{
    
    0,{
    
    23,53,20}}
7> calendar:seconds_to_daystime(86400).
{
    
    1,{
    
    0,0,0}}
8> calendar:seconds_to_daystime(1086400).
{
    
    12,{
    
    13,46,40}}
9> calendar:seconds_to_daystime(2086400).
{
    
    24,{
    
    3,33,20}}
10> calendar:seconds_to_daystime(3086400).
{
    
    35,{
    
    17,20,0}}

There are many interesting functions in the calendar interface, you can play with them

Whether the detection time is valid

13> calendar:valid_date(2021, 3, 31).
true
14> calendar:valid_date(2021, 3, 32).
false

Calculate the difference between two times

15> calendar:time_difference({
    
    {
    
    2021,3,28},{
    
    10,25,47}}, {
    
    {
    
    2021,3,29},{
    
    10,25,47}}).
{
    
    1,{
    
    0,0,0}}

Calculate today's day of the week

16> calendar:day_of_the_week({
    
    2021,3,28}).
7

Custom API

Effective detection time (with hours, minutes and seconds)

We found that the calendar library can only detect the year, month, and day, and we can add a combination of hours, minutes and seconds to detect

is_valid(time, {
    
    H, I, S}) ->
    H >= 0 andalso H < 24 andalso I >= 0 andalso I < 60 andalso S >= 0 andalso S < 60;
is_valid(datetime, {
    
    Date, Time}) ->
    calendat:valid_date(Date) andalso is_valid(time, Time);
is_valid(_, _) ->
    false.

Get 0 o'clock of the day

%%我们先获取当前时间戳
get_0() ->
    {
    
    M, S, MS} = ?MODULE:now(),
    %%拿到当前时间戳,如:{1617,67916,239852}
    {
    
    _, Time} = calendar:now_to_local_time({
    
    M, S, MS}),
    %%拿出时分秒,如:{_, Time} = {
    
    {2021,3,30},{9,31,56}}
    %%计算当天时分秒过去了多少秒
    M * 1000000 + S - calendar:time_to_seconds(Time).
%%即可得到当天0点的时间戳

Get 0 o'clock on the specified time day

For example, give a timestamp of 2020/12/12 12:12:12, find the timestamp of 0 o'clock that day

get_0(Time) ->
    %%先获取今天0点的时间戳
    Today_0 = get_0(),
    case Time > Today_0 of
        true ->
            %%如果求得是未来的时间,就直接先减,看差的秒数,整除86400,
            %%表示不满一天不算,大于一天小于两天算一天,没毛病吧,再乘一天的秒数
            %%得到相差的天数秒(86400 * n),再加上今天0点的就可以啦
            (Time - Today_0) div 86400 * 86400 + Today_0;
        false ->
            %%用今天的0点时间戳减去你求的那个时间戳,然后除以一天的秒数86400
            %%得到一个小数天数向上取整,比如你求的昨天的时间,用今天零点做减法得到零点几天
            %%向上取整就是一天,就是1 * 86400,再用今天0点时间戳减去86400就是前一天的0点时间戳啦
            Today - ceil((Today - Time) / 86400) * 86400
            %%下面放上ceil的实现
    end.


Expand ceil, floor

My understanding of the names of these two functions is, ceil ( ceiling function , look for the integer above), floor ( floor function , look for the integer below), I don’t know how you understand hahaha

%%我们知道erlang工具理里有一个trunc函数,功能是砍掉小数位,比如5.64464 -> 5,
%%可以借此实现ceil函数,这个其实很多语言都实现了,ceil floor 等,可以一并写出


%%求大于N的最小整数
ceil(N) ->
    M = erlang:trunc(N),
    case N > M of
        true -> M + 1;
        _ -> M
    end.
%%为什么会有砍掉小数还会比原来的数大的情况呢?你考虑负数没有咯



%%求小于N的最大整数
floor(N) ->
    M = erlang:trunc(N),
    case N < M of
        true -> M - 1;
        _ -> M
    end.
%%不解释了吧

Determine if the two times are the same day

Here we use the 0 point function above to judge

is_same_day(Time1, Time2) ->
    get_0(Time1) =:= get_0(Time2).

One more water

Determine if a time is today

See if 0 o'clock today is different from 0 o'clock this time

is_today(Time) ->
    get_0() =:= get_0(Time)

Find the number of days between two unixtimes

This is also achieved with the above zero point function. First, find out the number of days between the two days. If it is two adjacent days, we return 1. There is nothing wrong with the difference between today and yesterday by one day.

%%我们把小的天数放前面,然后大减小得到时间差,如果差秒除以一天秒(86400)小于1则返回0表示差的没有一天
%%如果大于1则用round函数,四舍五入就完了
day_diff(Time1, Time2) when Time2 > Time1 ->
    Time1_0 = get_0(Time1),
    Time2_0 = get_0(Time2),
    case (Time2_0 - Time1_0) / 86400 of
        Diff when Diff < 0 -> 0;
        Diff -> round(Diff)
    end;
day_diff(Time1, Time2) when Time1 =:= Time2 -> 0;
day_diff(TIme1, Time2) -> day_diff(Time2, Time1).

The difference in seconds between the current time and a certain time in the future

Get the hour, minute, and second of the current time, add the number of days difference N* the number of seconds in a day to the number of hours, minutes, and seconds of the day that you need to make the difference, and subtract the number of seconds, minutes, and seconds of the current time. It’s ok if you understand the code)

sss_diff(N, {
    
    H, I, S}) when is_integer(N), N >= 0 ->
    {
    
    _, Time} = ?MODULE:now(),
    N * 86400 + calendar:time_to_seconds({
    
    H, I, S}) - calendar:time_to_seconds(Time).

Guess you like

Origin blog.csdn.net/weixin_43876186/article/details/115320191