mbgtools-lx  4.2.8
mbgmktm.c
Go to the documentation of this file.
1 
2 /**************************************************************************
3  *
4  * $Id: mbgmktm.c 1.2 2017/07/05 10:00:29 martin REL_M $
5  *
6  * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
7  *
8  * Description:
9  * Function to convert broken down time to Unix time (seconds since 1970)
10  *
11  * -----------------------------------------------------------------------
12  * $Log: mbgmktm.c $
13  * Revision 1.2 2017/07/05 10:00:29 martin
14  * Let mbg_mktime() fail if year is out of a range which depends on
15  * the size of the 'time_t' type provided by the build environment.
16  * Allow 0 as valid return value for mbg_mktime().
17  * Added some doxygen comments.
18  * Revision 1.1 2006/08/22 08:57:15 martin
19  * Former function totalsec() moved here from pcpsmktm.c.
20  *
21  **************************************************************************/
22 
23 #define _MBGMKTM
24  #include <mbgmktm.h>
25 #undef _MBGMKTM
26 
27 #include <assert.h>
28 
29 
30 static const char Days[12] =
31 {
32  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
33 };
34 
35 static int YDays[12] =
36 {
37  0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
38 };
39 
40 
41 
42 /*HDR*/
61 time_t mbg_mktime( int year, int month, int day,
62  int hour, int min, int sec )
63 {
64  int leaps;
65  long days;
66  time_t secs;
67 
68  // time_t should be at least 4 bytes
69  assert( sizeof( time_t ) >= 4 );
70 
71  if ( sizeof( time_t ) == 4 )
72  {
73  // 32 bit *signed* time_t will roll over after 2038-01-19 03:14:07
74  // when the number of seconds reaches 0x7FFFFFFF, so we don't try
75  // conversions for 2038 or later, though 32 bit *unsigned* time_t
76  // may still work after year 2100.
77  if ( year < 70 || year > 137 )
78  goto fail;
79  }
80  else
81  if ( sizeof( time_t ) == 8 )
82  {
83  // 64 bit time_t will work for million years. However, it's not
84  // clear what happes for dates before 1970-01-01T00:00:00 if time_t
85  // is *unsigned*.
86  if ( year < 70 )
87  goto fail;
88  }
89  else
90  goto fail;
91 
92  min += sec / 60;
93  sec %= 60; /* Seconds are normalized */
94  hour += min / 60;
95  min %= 60; /* Minutes are normalized */
96  day += hour / 24;
97  hour %= 24; /* Hours are normalized */
98 
99  year += month / 12; /* Normalize month (not necessarily final) */
100  month %= 12;
101 
102  while ( day >= Days[month] )
103  {
104  if ( !( year & 3 ) && ( month == 1 ) )
105  {
106  if (day > 28)
107  {
108  day -= 29;
109  month++;
110  }
111  else
112  break;
113  }
114  else
115  {
116  day -= Days[month];
117  month++;
118  }
119 
120  year += month / 12; /* Normalize month */
121  month %= 12;
122  }
123 
124  year -= 70;
125  leaps = ( year + 2 ) / 4;
126 
127  if ( !( ( year + 70 ) & 3 ) && ( month < 2 ) )
128  --leaps;
129 
130  days = year * 365L + leaps + YDays[month] + day;
131 
132  secs = days * 86400L + hour * 3600L + min * 60L + sec;
133 
134  if ( secs < 0 ) // == 0 is valid for 1970-01-01 00:00:00
135  goto fail;
136 
137  return secs;
138 
139 
140 fail:
141  return (time_t) -1;
142 
143 } // mbg_mktime
144 
static int YDays[12]
Definition: mbgmktm.c:35
time_t mbg_mktime(int year, int month, int day, int hour, int min, int sec)
Compute a linear time_t value from broken down date and time.
Definition: mbgmktm.c:61
static const char Days[12]
Definition: mbgmktm.c:30