LCOV - code coverage report
Current view: top level - kernel/time - timeconv.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 40 0.0 %
Date: 2023-03-27 20:00:47 Functions: 0 1 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: LGPL-2.0+
       2             : /*
       3             :  * Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
       4             :  * This file is part of the GNU C Library.
       5             :  * Contributed by Paul Eggert (eggert@twinsun.com).
       6             :  *
       7             :  * The GNU C Library is free software; you can redistribute it and/or
       8             :  * modify it under the terms of the GNU Library General Public License as
       9             :  * published by the Free Software Foundation; either version 2 of the
      10             :  * License, or (at your option) any later version.
      11             :  *
      12             :  * The GNU C Library is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * Library General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Library General Public
      18             :  * License along with the GNU C Library; see the file COPYING.LIB.  If not,
      19             :  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      20             :  * Boston, MA 02111-1307, USA.
      21             :  */
      22             : 
      23             : /*
      24             :  * Converts the calendar time to broken-down time representation
      25             :  *
      26             :  * 2009-7-14:
      27             :  *   Moved from glibc-2.6 to kernel by Zhaolei<zhaolei@cn.fujitsu.com>
      28             :  * 2021-06-02:
      29             :  *   Reimplemented by Cassio Neri <cassio.neri@gmail.com>
      30             :  */
      31             : 
      32             : #include <linux/time.h>
      33             : #include <linux/module.h>
      34             : #include <linux/kernel.h>
      35             : 
      36             : #define SECS_PER_HOUR   (60 * 60)
      37             : #define SECS_PER_DAY    (SECS_PER_HOUR * 24)
      38             : 
      39             : /**
      40             :  * time64_to_tm - converts the calendar time to local broken-down time
      41             :  *
      42             :  * @totalsecs:  the number of seconds elapsed since 00:00:00 on January 1, 1970,
      43             :  *              Coordinated Universal Time (UTC).
      44             :  * @offset:     offset seconds adding to totalsecs.
      45             :  * @result:     pointer to struct tm variable to receive broken-down time
      46             :  */
      47           0 : void time64_to_tm(time64_t totalsecs, int offset, struct tm *result)
      48             : {
      49             :         u32 u32tmp, day_of_century, year_of_century, day_of_year, month, day;
      50             :         u64 u64tmp, udays, century, year;
      51             :         bool is_Jan_or_Feb, is_leap_year;
      52             :         long days, rem;
      53             :         int remainder;
      54             : 
      55           0 :         days = div_s64_rem(totalsecs, SECS_PER_DAY, &remainder);
      56           0 :         rem = remainder;
      57           0 :         rem += offset;
      58           0 :         while (rem < 0) {
      59           0 :                 rem += SECS_PER_DAY;
      60           0 :                 --days;
      61             :         }
      62           0 :         while (rem >= SECS_PER_DAY) {
      63           0 :                 rem -= SECS_PER_DAY;
      64           0 :                 ++days;
      65             :         }
      66             : 
      67           0 :         result->tm_hour = rem / SECS_PER_HOUR;
      68           0 :         rem %= SECS_PER_HOUR;
      69           0 :         result->tm_min = rem / 60;
      70           0 :         result->tm_sec = rem % 60;
      71             : 
      72             :         /* January 1, 1970 was a Thursday. */
      73           0 :         result->tm_wday = (4 + days) % 7;
      74           0 :         if (result->tm_wday < 0)
      75           0 :                 result->tm_wday += 7;
      76             : 
      77             :         /*
      78             :          * The following algorithm is, basically, Proposition 6.3 of Neri
      79             :          * and Schneider [1]. In a few words: it works on the computational
      80             :          * (fictitious) calendar where the year starts in March, month = 2
      81             :          * (*), and finishes in February, month = 13. This calendar is
      82             :          * mathematically convenient because the day of the year does not
      83             :          * depend on whether the year is leap or not. For instance:
      84             :          *
      85             :          * March 1st            0-th day of the year;
      86             :          * ...
      87             :          * April 1st            31-st day of the year;
      88             :          * ...
      89             :          * January 1st          306-th day of the year; (Important!)
      90             :          * ...
      91             :          * February 28th        364-th day of the year;
      92             :          * February 29th        365-th day of the year (if it exists).
      93             :          *
      94             :          * After having worked out the date in the computational calendar
      95             :          * (using just arithmetics) it's easy to convert it to the
      96             :          * corresponding date in the Gregorian calendar.
      97             :          *
      98             :          * [1] "Euclidean Affine Functions and Applications to Calendar
      99             :          * Algorithms". https://arxiv.org/abs/2102.06959
     100             :          *
     101             :          * (*) The numbering of months follows tm more closely and thus,
     102             :          * is slightly different from [1].
     103             :          */
     104             : 
     105           0 :         udays   = ((u64) days) + 2305843009213814918ULL;
     106             : 
     107           0 :         u64tmp          = 4 * udays + 3;
     108           0 :         century         = div64_u64_rem(u64tmp, 146097, &u64tmp);
     109           0 :         day_of_century  = (u32) (u64tmp / 4);
     110             : 
     111           0 :         u32tmp          = 4 * day_of_century + 3;
     112           0 :         u64tmp          = 2939745ULL * u32tmp;
     113           0 :         year_of_century = upper_32_bits(u64tmp);
     114           0 :         day_of_year     = lower_32_bits(u64tmp) / 2939745 / 4;
     115             : 
     116           0 :         year            = 100 * century + year_of_century;
     117           0 :         is_leap_year    = year_of_century ? !(year_of_century % 4) : !(century % 4);
     118             : 
     119           0 :         u32tmp          = 2141 * day_of_year + 132377;
     120           0 :         month           = u32tmp >> 16;
     121           0 :         day             = ((u16) u32tmp) / 2141;
     122             : 
     123             :         /*
     124             :          * Recall that January 1st is the 306-th day of the year in the
     125             :          * computational (not Gregorian) calendar.
     126             :          */
     127           0 :         is_Jan_or_Feb   = day_of_year >= 306;
     128             : 
     129             :         /* Convert to the Gregorian calendar and adjust to Unix time. */
     130           0 :         year            = year + is_Jan_or_Feb - 6313183731940000ULL;
     131           0 :         month           = is_Jan_or_Feb ? month - 12 : month;
     132           0 :         day             = day + 1;
     133           0 :         day_of_year     += is_Jan_or_Feb ? -306 : 31 + 28 + is_leap_year;
     134             : 
     135             :         /* Convert to tm's format. */
     136           0 :         result->tm_year = (long) (year - 1900);
     137           0 :         result->tm_mon  = (int) month;
     138           0 :         result->tm_mday = (int) day;
     139           0 :         result->tm_yday = (int) day_of_year;
     140           0 : }
     141             : EXPORT_SYMBOL(time64_to_tm);

Generated by: LCOV version 1.14