1*16287fabSjakllsch /* $NetBSD: clock_subr.c,v 1.27 2016/08/15 15:51:39 jakllsch Exp $ */
2aad01611Sagc
3aad01611Sagc /*
49b6bd2d9Srmind * Copyright (c) 1988 University of Utah.
5aad01611Sagc * Copyright (c) 1982, 1990, 1993
6aad01611Sagc * The Regents of the University of California. All rights reserved.
7aad01611Sagc *
8aad01611Sagc * This code is derived from software contributed to Berkeley by
9aad01611Sagc * the Systems Programming Group of the University of Utah Computer
10aad01611Sagc * Science Department.
11aad01611Sagc *
12aad01611Sagc * Redistribution and use in source and binary forms, with or without
13aad01611Sagc * modification, are permitted provided that the following conditions
14aad01611Sagc * are met:
15aad01611Sagc * 1. Redistributions of source code must retain the above copyright
16aad01611Sagc * notice, this list of conditions and the following disclaimer.
17aad01611Sagc * 2. Redistributions in binary form must reproduce the above copyright
18aad01611Sagc * notice, this list of conditions and the following disclaimer in the
19aad01611Sagc * documentation and/or other materials provided with the distribution.
20aad01611Sagc * 3. Neither the name of the University nor the names of its contributors
21aad01611Sagc * may be used to endorse or promote products derived from this software
22aad01611Sagc * without specific prior written permission.
23aad01611Sagc *
24aad01611Sagc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25aad01611Sagc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26aad01611Sagc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27aad01611Sagc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28aad01611Sagc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29aad01611Sagc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30aad01611Sagc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31aad01611Sagc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32aad01611Sagc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33aad01611Sagc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34aad01611Sagc * SUCH DAMAGE.
35aad01611Sagc *
36aad01611Sagc * from: Utah $Hdr: clock.c 1.18 91/01/21$
37aad01611Sagc *
38aad01611Sagc * @(#)clock.c 8.2 (Berkeley) 1/12/94
39aad01611Sagc */
40d8b59a12Sgwr
41d8b59a12Sgwr /*
42d8b59a12Sgwr * Generic routines to convert between a POSIX date
43d8b59a12Sgwr * (seconds since 1/1/1970) and yr/mo/day/hr/min/sec
44d8b59a12Sgwr * Derived from arch/hp300/hp300/clock.c
45d8b59a12Sgwr */
46d8b59a12Sgwr
47d2f4f342Sapb #if HAVE_NBTOOL_CONFIG_H
48d2f4f342Sapb #include "nbtool_config.h"
49d2f4f342Sapb #endif /* HAVE_NBTOOL_CONFIG_H */
50d2f4f342Sapb
510edf2e8fSmartin #ifdef _KERNEL
522bbe2de6Slukem #include <sys/cdefs.h>
53*16287fabSjakllsch __KERNEL_RCSID(0, "$NetBSD: clock_subr.c,v 1.27 2016/08/15 15:51:39 jakllsch Exp $");
542bbe2de6Slukem
55303f5332Sragge #include <sys/param.h>
56d8b59a12Sgwr #include <sys/systm.h>
575621a8b9Smartin #include <sys/errno.h>
58d2f4f342Sapb #else /* ! _KERNEL */
590edf2e8fSmartin #include <string.h>
600edf2e8fSmartin #include <time.h>
615621a8b9Smartin #include <errno.h>
62d2f4f342Sapb #endif /* ! _KERNEL */
63d8b59a12Sgwr
647e52766bSjoerg #include "../sys/clock.h"
65d8b59a12Sgwr #include <dev/clock_subr.h>
66d8b59a12Sgwr
67d8b59a12Sgwr #define FEBRUARY 2
68d8b59a12Sgwr
6997f844c0Smartin /* for easier alignment:
70*16287fabSjakllsch * time from the epoch to 2001 (there were 8 leap years): */
71*16287fabSjakllsch #define DAYSTO2001 (365*31+8)
7297f844c0Smartin
7397f844c0Smartin /* 4 year intervals include 1 leap year */
7497f844c0Smartin #define DAYS4YEARS (365*4+1)
7597f844c0Smartin
7697f844c0Smartin /* 100 year intervals include 24 leap years */
7797f844c0Smartin #define DAYS100YEARS (365*100+24)
7897f844c0Smartin
7997f844c0Smartin /* 400 year intervals include 97 leap years */
8097f844c0Smartin #define DAYS400YEARS (365*400+97)
8197f844c0Smartin
82d8b59a12Sgwr time_t
clock_ymdhms_to_secs(struct clock_ymdhms * dt)8388e7f0dcSperry clock_ymdhms_to_secs(struct clock_ymdhms *dt)
84d8b59a12Sgwr {
855621a8b9Smartin uint64_t secs, i, year, days;
86d8b59a12Sgwr
87d8b59a12Sgwr year = dt->dt_year;
88d8b59a12Sgwr
89d8b59a12Sgwr /*
90d8b59a12Sgwr * Compute days since start of time
91d8b59a12Sgwr * First from years, then from months.
92d8b59a12Sgwr */
936621c5bdStsutsui if (year < POSIX_BASE_YEAR)
946621c5bdStsutsui return -1;
95d8b59a12Sgwr days = 0;
96a95736d4Schristos if (is_leap_year(year) && dt->dt_mon > FEBRUARY)
97d8b59a12Sgwr days++;
98d8b59a12Sgwr
99*16287fabSjakllsch if (year < 2001) {
10097f844c0Smartin /* simple way for early years */
10197f844c0Smartin for (i = POSIX_BASE_YEAR; i < year; i++)
102a95736d4Schristos days += days_per_year(i);
10397f844c0Smartin } else {
10497f844c0Smartin /* years are properly aligned */
105*16287fabSjakllsch days += DAYSTO2001;
106*16287fabSjakllsch year -= 2001;
10797f844c0Smartin
10897f844c0Smartin i = year / 400;
10997f844c0Smartin days += i * DAYS400YEARS;
11097f844c0Smartin year -= i * 400;
11197f844c0Smartin
11297f844c0Smartin i = year / 100;
11397f844c0Smartin days += i * DAYS100YEARS;
11497f844c0Smartin year -= i * 100;
11597f844c0Smartin
11697f844c0Smartin i = year / 4;
11797f844c0Smartin days += i * DAYS4YEARS;
11897f844c0Smartin year -= i * 4;
11997f844c0Smartin
12097f844c0Smartin for (i = dt->dt_year-year; i < dt->dt_year; i++)
12153bfb03cSchristos days += days_per_year(i);
12297f844c0Smartin }
12397f844c0Smartin
12497f844c0Smartin
125d8b59a12Sgwr /* Months */
126d8b59a12Sgwr for (i = 1; i < dt->dt_mon; i++)
127d8b59a12Sgwr days += days_in_month(i);
128d8b59a12Sgwr days += (dt->dt_day - 1);
129d8b59a12Sgwr
130d8b59a12Sgwr /* Add hours, minutes, seconds. */
1318f7f78f2Sbjh21 secs = (((uint64_t)days
132d8b59a12Sgwr * 24 + dt->dt_hour)
133d8b59a12Sgwr * 60 + dt->dt_min)
134d8b59a12Sgwr * 60 + dt->dt_sec;
135d8b59a12Sgwr
1365b258ea3Sapb if ((time_t)secs < 0 || secs > __type_max(time_t))
1376621c5bdStsutsui return -1;
1386621c5bdStsutsui return secs;
139d8b59a12Sgwr }
140d8b59a12Sgwr
1415621a8b9Smartin int
clock_secs_to_ymdhms(time_t secs,struct clock_ymdhms * dt)14288e7f0dcSperry clock_secs_to_ymdhms(time_t secs, struct clock_ymdhms *dt)
143d8b59a12Sgwr {
1445621a8b9Smartin int leap;
1455621a8b9Smartin uint64_t i;
146bf749939Stsutsui time_t days;
147bf749939Stsutsui time_t rsec; /* remainder seconds */
148d8b59a12Sgwr
1495621a8b9Smartin if (secs < 0)
1505621a8b9Smartin return EINVAL;
1515621a8b9Smartin
152a95736d4Schristos days = secs / SECS_PER_DAY;
153a95736d4Schristos rsec = secs % SECS_PER_DAY;
154d8b59a12Sgwr
155d8b59a12Sgwr /* Day of week (Note: 1/1/1970 was a Thursday) */
156d8b59a12Sgwr dt->dt_wday = (days + 4) % 7;
157d8b59a12Sgwr
158*16287fabSjakllsch if (days >= DAYSTO2001) {
159*16287fabSjakllsch days -= DAYSTO2001;
160*16287fabSjakllsch dt->dt_year = 2001;
16197f844c0Smartin
16297f844c0Smartin i = days / DAYS400YEARS;
16397f844c0Smartin days -= i*DAYS400YEARS;
16497f844c0Smartin dt->dt_year += i*400;
16597f844c0Smartin
16697f844c0Smartin i = days / DAYS100YEARS;
16797f844c0Smartin days -= i*DAYS100YEARS;
16897f844c0Smartin dt->dt_year += i*100;
16997f844c0Smartin
17097f844c0Smartin i = days / DAYS4YEARS;
17197f844c0Smartin days -= i*DAYS4YEARS;
17297f844c0Smartin dt->dt_year += i*4;
17397f844c0Smartin
174a95736d4Schristos for (i = dt->dt_year; days >= days_per_year(i); i++)
175a95736d4Schristos days -= days_per_year(i);
17697f844c0Smartin dt->dt_year = i;
17797f844c0Smartin } else {
178d8b59a12Sgwr /* Subtract out whole years, counting them in i. */
179a95736d4Schristos for (i = POSIX_BASE_YEAR; days >= days_per_year(i); i++)
180a95736d4Schristos days -= days_per_year(i);
181d8b59a12Sgwr dt->dt_year = i;
18297f844c0Smartin }
183d8b59a12Sgwr
184d8b59a12Sgwr /* Subtract out whole months, counting them in i. */
18597f844c0Smartin for (leap = 0, i = 1; days >= days_in_month(i)+leap; i++) {
18697f844c0Smartin days -= days_in_month(i)+leap;
187a95736d4Schristos if (i == 1 && is_leap_year(dt->dt_year))
18897f844c0Smartin leap = 1;
18997f844c0Smartin else
19097f844c0Smartin leap = 0;
19197f844c0Smartin }
192d8b59a12Sgwr dt->dt_mon = i;
193d8b59a12Sgwr
194d8b59a12Sgwr /* Days are what is left over (+1) from all that. */
195d8b59a12Sgwr dt->dt_day = days + 1;
196d8b59a12Sgwr
197d8b59a12Sgwr /* Hours, minutes, seconds are easy */
1988694ecf4Schristos dt->dt_hour = rsec / SECS_PER_HOUR;
1998694ecf4Schristos rsec = rsec % SECS_PER_HOUR;
2008694ecf4Schristos dt->dt_min = rsec / SECS_PER_MINUTE;
2018694ecf4Schristos rsec = rsec % SECS_PER_MINUTE;
202d8b59a12Sgwr dt->dt_sec = rsec;
2035621a8b9Smartin
2045621a8b9Smartin return 0;
205d8b59a12Sgwr }
206