Calculate day number from an unix-timestamp in a math way?

后端 未结 3 1984
一整个雨季
一整个雨季 2021-01-12 08:13

How can i calculate day number from a unix-timestamp, in a mathematical way and without using any functions and in simple math formula.

1313905026 --> 8 (Today 08/21

相关标签:
3条回答
  • 2021-01-12 08:25
    t = unix time
    second = t MOD 60  
    minute = INT(t / 60) MOD 60  
    hour = INT(t / 60 / 60) MOD 24  
    days = INT(t / 60 / 60 / 24)  
    years = INT(days / 365.25)  
    year = 1970 + years + 1
    

    1970 started with a Thursday so, we can calculate the day of the week:

    weekday = (days + 4) MOD 7
    

    If Sunday is day 0. If you want Sunday to be day 1 just add 1.

    Now, let's find out how many days we are into the year in question.

    days = days - years * 365 - leapdays
    

    Finally, we find the month and day of the month.

    IF year MOD 4 = 0 THEN ly = 1 ELSE ly = 0
    WHILE month <= 12
        month = month + 1
        IF month = 2 THEN
            DaysInMonth = 28 + NOT(year MOD 4) + NOT(year MOD 100)
                + NOT(year MOD 400)
        ELSE
            DaysInMonth = 30 + (month + (month < 7)) MOD 2
        END IF
        IF days > DaysInMonth THEN days = days - DaysInMonth
    END WHILE
    

    This assumes Boolean values of TRUE = 1, FALSE = 0, NOT TRUE = 0, and NOT FALSE = 1.

    Now we have the year, month, day of the month, hour, minute, and second calculated with adjustments for leap years.

    0 讨论(0)
  • 2021-01-12 08:47

    There is no simple formula to do this. You would need to subtract the number of years (accounting for leap years) since the epoch, which would probably require a loop or a discrete calculation of some kind. Then use some type of loop to subtract out the number of seconds in each month for the current year. What you are left with is the number of seconds currently into the month.

    I would do something like this.

    x = ...//the number of seconds
    year = 1970
    
    while (x > /*one year*/){
     x = x - /*seconds in january, and march-december*/
     if(year % 4 == 0){
      x -= /*leapeay seconds in february*/
     }else{
      x -= /*regular seconds in february*/
     }
    }
    
    //Then something like this:
    
    if(x > /*seconds in january*/){
     x -= /*seconds in january*/
    }
    if(x > /*seconds in february*/){
     x -= /*seconds in january*/
    }
    
    .
    .
    .
    
    //After that just get the number of days from x seconds and you're set.
    

    Edit

    I recommend using date functions for simplicity, but here is a possible non-loopy alternative answer in case anyone needs it, or would care to develop it further.

    First let t be the current time in seconds since the epoch.

    Let F be the number of seconds in four years. That is three regular years and one leap year. That should be: 126230400.

    Now if you take away all of the time contributed by F, you will get a remainder: y.

    So y = n % F.

    There are several cases now: 1. y is less that one year 2. y is less than two years 3. y is less than three years and less than two months 4. y is less than three years and greater than two months 5. y is less than four years

    Note that 1972 was a leap year, so if you count up by four from 1970, wherever you left off will be a leap year in two years.

    let jan, feb, febLY, mar, may, ..., dec be the number of seconds in each month (you'd need to calculate it out).

    d represents the day number of the current month and D represents the number of seconds in a day (86400). y represents the number of seconds in a regular year, and yLY represents the number of seconds in a leap year.

    y = (t % F)
    if(y < Y){
     if(y > jan){
      y -= jan
     }
     if(y > feb){
      y -= feb
     }
     .
     .
     .
     d = y % D
    }
    else if(y < 2 * y){
     y = y - Y
     if(y > jan){
      y -= jan
     }
     if(y > feb){
      y -= feb
     }
     .
     .
     .
     d = y % D
    }
    else if(y < 2 * y + yLY){
     y = y - 2 * Y
     if(y > jan){
      y -= jan
     }
     if(y > febLY){
      y -= febLY
     }
     .
     .
     .
     d = y % D
    }
    else{
     y = y - 2 * Y - yLY
     if(y > jan){
      y -= jan
     }
     if(y > feb){
      y -= feb
     }
     .
     .
     .
     d = y % D
    }
    

    Not tested. Also, since the Earth doesn't spin at EXACTLY 1 rotation / 24 hours, they've occasionally made adjustments to time. You need to do a bit of research factor that in.

    0 讨论(0)
  • 2021-01-12 08:49

    A unix timestamp doesn't include leap seconds, so we don't have to worry about that. Here is a branch-less1, loop-less algorithm for getting the y/m/d fields from a unix timestamp:

    #include <iostream>
    
    int
    main()
    {
        int s = 1313905026;
        int z = s / 86400 + 719468;
        int era = (z >= 0 ? z : z - 146096) / 146097;
        unsigned doe = static_cast<unsigned>(z - era * 146097);
        unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365;
        int y = static_cast<int>(yoe) + era * 400;
        unsigned doy = doe - (365*yoe + yoe/4 - yoe/100);
        unsigned mp = (5*doy + 2)/153;
        unsigned d = doy - (153*mp+2)/5 + 1;
        unsigned m = mp + (mp < 10 ? 3 : -9);
        y += (m <= 2);
        std::cout << m << '/' << d << '/' << y << '\n'; // 8/21/2011
    }
    

    This outputs:

    8/21/2011
    

    As you're not interested in y and m (only in d), you can eliminate the last couple of lines from the above computation.

    This algorithm is described in excruciating detail here. The link includes a complete derivation, and unit tests spanning millions of years (which is overkill).


    1 Branch-less: What looks like small branches in the algorithm above are optimized away by clang at -O3 on macOS:

    __Z14get_day_numberi:                   ## @_Z14get_day_numberi
        .cfi_startproc
    ## BB#0:
        pushq   %rbp
    Ltmp0:
        .cfi_def_cfa_offset 16
    Ltmp1:
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp
    Ltmp2:
        .cfi_def_cfa_register %rbp
        movslq  %edi, %rax
        imulq   $-1037155065, %rax, %rcx ## imm = 0xFFFFFFFFC22E4507
        shrq    $32, %rcx
        addl    %ecx, %eax
        movl    %eax, %ecx
        shrl    $31, %ecx
        sarl    $16, %eax
        leal    (%rax,%rcx), %edx
        leal    719468(%rax,%rcx), %esi
        testl   %esi, %esi
        leal    573372(%rax,%rcx), %eax
        cmovnsl %esi, %eax
        cltq
        imulq   $963315389, %rax, %rcx  ## imm = 0x396B06BD
        movq    %rcx, %rsi
        shrq    $63, %rsi
        shrq    $32, %rcx
        sarl    $15, %ecx
        addl    %esi, %ecx
        imull   $146097, %ecx, %ecx     ## imm = 0x23AB1
        movl    %eax, %esi
        subl    %ecx, %esi
        subl    %eax, %esi
        leal    719468(%rsi,%rdx), %eax
        movl    %eax, %ecx
        shrl    $2, %ecx
        imulq   $1506180313, %rcx, %rdx ## imm = 0x59C67CD9
        shrq    $39, %rdx
        movl    %eax, %esi
        subl    %edx, %esi
        imulq   $963321983, %rcx, %rcx  ## imm = 0x396B207F
        shrq    $43, %rcx
        addl    %esi, %ecx
        movl    %eax, %edx
        shrl    $4, %edx
        imulq   $7525953, %rdx, %rdx    ## imm = 0x72D641
        shrq    $36, %rdx
        subl    %edx, %ecx
        imulq   $1729753953, %rcx, %rsi ## imm = 0x6719F361
        shrq    $32, %rsi
        movl    %ecx, %r8d
        subl    %ecx, %eax
        movl    %ecx, %edi
        movl    $3855821599, %edx       ## imm = 0xE5D32B1F
        imulq   %rcx, %rdx
        subl    %esi, %ecx
        shrl    %ecx
        addl    %esi, %ecx
        shrl    $8, %ecx
        imull   $365, %ecx, %ecx        ## imm = 0x16D
        subl    %ecx, %r8d
        shrl    $2, %edi
        imulq   $1506180313, %rdi, %rcx ## imm = 0x59C67CD9
        shrq    $39, %rcx
        shrq    $47, %rdx
        addl    %r8d, %eax
        subl    %ecx, %eax
        leal    (%rax,%rdx), %ecx
        leal    2(%rcx,%rcx,4), %esi
        movl    $3593175255, %edi       ## imm = 0xD62B80D7
        imulq   %rsi, %rdi
        shrq    $39, %rdi
        imull   $153, %edi, %edi
        subl    %edi, %esi
        leal    4(%rcx,%rcx,4), %ecx
        subl    %esi, %ecx
        movl    $3435973837, %esi       ## imm = 0xCCCCCCCD
        imulq   %rcx, %rsi
        shrq    $34, %rsi
        leal    1(%rax,%rdx), %eax
        subl    %esi, %eax
        popq    %rbp
        retq
        .cfi_endproc
    
    0 讨论(0)
提交回复
热议问题