00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "midgard/midgard_timestamp.h"
00020 #include <glib.h>
00021
00022 struct caltime {
00023 long year;
00024 int month;
00025 int day;
00026 int hour;
00027 int minute;
00028 int second;
00029 unsigned long nano;
00030 long offset;
00031 };
00032
00033 #define leapsecs_add(a,b) (a)
00034
00035 static const gchar *caltime_fmt(struct caltime *ct) {
00036 GString *string = g_string_sized_new(100);
00037 g_string_printf(
00038 string, "%ld-%02d-%02d %02d:%02d:%02d",
00039 ct->year, ct->month, ct->day, ct->hour, ct->minute, ct->second);
00040 if (ct->nano > 0) {
00041 unsigned long n = ct->nano;
00042 while ((n % 10) == 0) { n = n / 10; }
00043 g_string_append_printf(string, ".%lo", n);
00044 }
00045 g_string_append_printf(string, "%+05ld", ct->offset);
00046 return g_string_free(string, FALSE);
00047 }
00048
00049 static unsigned int caltime_scan(const char *s, struct caltime *ct) {
00050 int sign = 1;
00051 const char *t = s;
00052 unsigned long z;
00053 unsigned long c;
00054
00055 if (*t == '-') { ++t; sign = -1; }
00056 z = 0; while ((c = (unsigned char) (*t - '0')) <= 9) { z = z * 10 + c; ++t; }
00057 ct->year = z * sign;
00058
00059 if (*t++ != '-') return 0;
00060 z = 0; while ((c = (unsigned char) (*t - '0')) <= 9) { z = z * 10 + c; ++t; }
00061 ct->month = z;
00062
00063 if (*t++ != '-') return 0;
00064 z = 0; while ((c = (unsigned char) (*t - '0')) <= 9) { z = z * 10 + c; ++t; }
00065 ct->day = z;
00066
00067 while ((*t == ' ') || (*t == '\t') || (*t == 'T')) ++t;
00068 z = 0; while ((c = (unsigned char) (*t - '0')) <= 9) { z = z * 10 + c; ++t; }
00069 ct->hour = z;
00070
00071 if (*t++ != ':') return 0;
00072 z = 0; while ((c = (unsigned char) (*t - '0')) <= 9) { z = z * 10 + c; ++t; }
00073 ct->minute = z;
00074
00075 if (*t != ':')
00076 ct->second = 0;
00077 else {
00078 ++t;
00079 z = 0; while ((c = (unsigned char) (*t - '0')) <= 9) { z = z * 10 + c; ++t; }
00080 ct->second = z;
00081 }
00082
00083 if (*t != '.')
00084 ct->nano = 0;
00085 else {
00086 ++t;
00087 ct->nano = 1000000000;
00088 z = 0; while ((c = (unsigned char) (*t - '0')) <= 9) { if (ct->nano > 1) { z = z * 10 + c; ++t; ct->nano /= 10; } }
00089 ct->nano *= z;
00090 }
00091
00092 while ((*t == ' ') || (*t == '\t')) ++t;
00093 if (*t == '+') sign = 1; else if (*t == '-') sign = -1; else return 0;
00094 ++t;
00095 c = (unsigned char) (*t++ - '0'); if (c > 9) return 0; z = c;
00096 c = (unsigned char) (*t++ - '0'); if (c > 9) return 0; z = z * 10 + c;
00097 c = (unsigned char) (*t++ - '0'); if (c > 9) return 0; z = z * 6 + c;
00098 c = (unsigned char) (*t++ - '0'); if (c > 9) return 0; z = z * 10 + c;
00099 ct->offset = z * sign;
00100
00101 return t - s;
00102 }
00103
00104 static void midgard_timestamp_get_caltime(
00105 const GValue *value, struct caltime *ct) {
00106 guint64 u = value->data[0].v_uint64 + 58486;
00107 long s = u % 86400ULL;
00108 long day = u / 86400ULL - 53375995543064ULL;
00109 long year = day / 146097L;
00110 long month;
00111
00112
00113 ct->second = s % 60; s /= 60;
00114 ct->minute = s % 60; s /= 60;
00115 ct->hour = s;
00116
00117 day = (day % 146097L) + 678881L;
00118 while (day >= 146097L) { day -= 146097L; ++year; }
00119
00120
00121
00122
00123 year *= 4;
00124 if (day == 146096L) { year += 3; day = 36524L; }
00125 else { year += day / 36524L; day %= 36524L; }
00126 year = year * 25 + day / 1461;
00127 day %= 1461;
00128 year *= 4;
00129
00130 if (day == 1460) { year += 3; day = 365; }
00131 else { year += day / 365; day %= 365; }
00132
00133 day *= 10;
00134 month = (day + 5) / 306;
00135 day = (day + 5) % 306;
00136 day /= 10;
00137 if (month >= 10) { ++year; month -= 10; }
00138 else { month += 2; }
00139
00140 ct->year = year;
00141 ct->month = month + 1;
00142 ct->day = day + 1;
00143
00144 ct->offset = 0;
00145 ct->nano = value->data[1].v_ulong;
00146 }
00147
00148 static void midgard_timestamp_set_caltime(
00149 GValue *value, const struct caltime *ct) {
00150 static const unsigned long times365[4] = { 0, 365, 730, 1095 };
00151 static const unsigned long times36524[4] = { 0, 36524UL, 73048UL, 109572UL };
00152 static const unsigned long montab[12] =
00153 { 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337 };
00154
00155
00156 long y = ct->year;
00157 long m = ct->month - 1;
00158 long d = ct->day - 678882L;
00159 long s = ((ct->hour * 60 + ct->minute) - ct->offset) * 60 + ct->second;
00160
00161 d += 146097L * (y / 400);
00162 y %= 400;
00163
00164 if (m >= 2) m -= 2; else { m += 10; --y; }
00165
00166 y += (m / 12);
00167 m %= 12;
00168 if (m < 0) { m += 12; --y; }
00169
00170 d += montab[m];
00171
00172 d += 146097L * (y / 400);
00173 y %= 400;
00174 if (y < 0) { y += 400; d -= 146097L; }
00175
00176 d += times365[y & 3];
00177 y >>= 2;
00178
00179 d += 1461L * (y % 25);
00180 y /= 25;
00181
00182 d += times36524[y & 3];
00183
00184 value->data[0].v_uint64 =
00185 d * 86400ULL + 4611686014920671114ULL + (long long) s;
00186 value->data[1].v_ulong = ct->nano;
00187
00188 }
00189
00190
00191
00192 static void value_init_timestamp(GValue *value) {
00193 g_assert(G_VALUE_HOLDS(value, MIDGARD_TYPE_TIMESTAMP));
00194
00195 value->data[0].v_uint64 = 4611686018427387914ULL;
00196 value->data[1].v_ulong = 0;
00197 }
00198
00199
00200 static void value_copy_timestamp(const GValue *src, GValue *dst) {
00201 g_assert(G_VALUE_HOLDS(src, MIDGARD_TYPE_TIMESTAMP));
00202 g_assert(G_VALUE_HOLDS(dst, MIDGARD_TYPE_TIMESTAMP));
00203
00204 dst->data[0].v_uint64 = src->data[0].v_uint64;
00205 dst->data[1].v_ulong = src->data[1].v_ulong;
00206 }
00207
00208
00209 static gchar *value_collect_timestamp(
00210 GValue *value, guint n_collect_values,
00211 GTypeCValue *collect_values, guint collect_flags) {
00212 g_assert(G_VALUE_HOLDS(value, MIDGARD_TYPE_TIMESTAMP));
00213 g_assert(n_collect_values == 1);
00214 g_assert(collect_values != NULL);
00215
00216 const gchar *time = (const gchar *) collect_values;
00217 if (time == NULL) {
00218 return g_strdup("Midgard timestamp value string passed as NULL");
00219 }
00220
00221 return NULL;
00222 }
00223
00224
00225 static gchar *value_lcopy_timestamp(
00226 const GValue *value, guint n_collect_values,
00227 GTypeCValue *collect_values, guint collect_flags) {
00228 g_assert(G_VALUE_HOLDS(value, MIDGARD_TYPE_TIMESTAMP));
00229 g_assert(n_collect_values == 1);
00230 g_assert(collect_values != NULL);
00231
00232 const gchar **time = (const gchar **) collect_values;
00233 if (time == NULL) {
00234 return g_strdup("Midgard timestamp value string passed as NULL");
00235 }
00236
00237 return NULL;
00238 }
00239
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 GType midgard_timestamp_get_type(void) {
00263 static GType type = 0;
00264 if (type == 0) {
00265 static const GTypeValueTable value_table = {
00266 &value_init_timestamp,
00267 NULL,
00268 &value_copy_timestamp,
00269 NULL,
00270 "p",
00271 &value_collect_timestamp,
00272 "p",
00273 &value_lcopy_timestamp
00274 };
00275 static const GTypeInfo info = {
00276 0,
00277 NULL,
00278 NULL,
00279 NULL,
00280 NULL,
00281 NULL,
00282 0,
00283 0,
00284 NULL,
00285 &value_table
00286 };
00287 static const GTypeFundamentalInfo finfo = {
00288 G_TYPE_FLAG_DERIVABLE
00289 };
00290 type = g_type_register_fundamental(
00291 g_type_fundamental_next(), "midgard_timestamp",
00292 &info, &finfo, 0);
00293 }
00294 return type;
00295 }
00296
00297 gchar *midgard_timestamp_dup_string(const GValue *value) {
00298 g_assert(G_VALUE_HOLDS(value, MIDGARD_TYPE_TIMESTAMP));
00299 struct caltime ct;
00300 midgard_timestamp_get_caltime(value, &ct);
00301 return (gchar *)caltime_fmt(&ct);
00302 }
00303
00304 void midgard_timestamp_set_string(GValue *value, const gchar *time) {
00305 g_assert(G_VALUE_HOLDS(value, MIDGARD_TYPE_TIMESTAMP));
00306 g_assert(time != NULL);
00307
00308 struct caltime ct;
00309 if (caltime_scan(time, &ct) > 0) {
00310 midgard_timestamp_set_caltime(value, &ct);
00311 } else {
00312 value->data[0].v_uint64 = 4611686018427387914ULL;
00313 value->data[1].v_ulong = 0;
00314 }
00315 }
00316
00317 time_t midgard_timestamp_get_time(const GValue *value) {
00318 g_assert(G_VALUE_HOLDS(value, MIDGARD_TYPE_TIMESTAMP));
00319
00320 if (value->data[1].v_ulong >= 1000000000 / 2) {
00321 return value->data[0].v_uint64 - 4611686018427387914ULL + 1;
00322 } else {
00323 return value->data[0].v_uint64 - 4611686018427387914ULL;
00324 }
00325 }
00326
00327 void midgard_timestamp_set_time(GValue *value, time_t time) {
00328 g_assert(G_VALUE_HOLDS(value, MIDGARD_TYPE_TIMESTAMP));
00329
00330 value->data[0].v_uint64 = time + 4611686018427387914ULL;
00331 value->data[1].v_ulong = 0;
00332 }