src/midgard_timestamp.c

00001 /*
00002  * Copyright (c) 2005 Jukka Zitting <jz@yukatan.fi>
00003  *
00004  * This program is free software; you can redistribute it and/or modify it
00005  * under the terms of the GNU Lesser General Public License as published
00006  * by the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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   /* int yday; */
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   /* year * 146097 + day - 678881 is MJD; 0 <= day < 146097 */
00121   /* 2000-03-01, MJD 51604, is year 5, day 0 */
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     /* month length after february is (306 * m + 5) / 10 */
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   /* TODO: leapsecs */
00188 }
00189 
00190 
00191 /* Internal initialization function for the midgard_timestamp value type. */
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 /* Internal copy function for the midgard_timestamp value type. */
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 /* Internal collect function for the midgard_timestamp value type. */
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 /* Internal lcopy function for the midgard_timestamp value type. */
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 /* Not used , commented */
00242 /* 
00243 static void midgard_timestamp_to_string(const GValue *src, GValue *dst) {
00244         g_assert(G_VALUE_HOLDS(src, MIDGARD_TYPE_TIMESTAMP));
00245         g_assert(G_VALUE_HOLDS(dst, G_TYPE_STRING));
00246 
00247         g_value_take_string(dst, midgard_timestamp_dup_string(src));
00248 }
00249 */
00250 
00252 /* Not used, commented */
00253 /*
00254 static void midgard_timestamp_from_string(const GValue *src, GValue *dst) {
00255         g_assert(G_VALUE_HOLDS(src, G_TYPE_STRING));
00256         g_assert(G_VALUE_HOLDS(dst, MIDGARD_TYPE_TIMESTAMP));
00257 
00258         midgard_timestamp_set_string(dst, g_value_get_string(src));
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,     /* value_init */
00267                         NULL,                      /* value_free */
00268                         &value_copy_timestamp,     /* value_copy */
00269                         NULL,                      /* value_peek_pointer */
00270                         "p",                       /* collect_format */
00271                         &value_collect_timestamp,  /* collect_value */
00272                         "p",                       /* lcopy_format */
00273                         &value_lcopy_timestamp     /* lcopy_value */
00274                 };
00275                 static const GTypeInfo info = {
00276                         0,                         /* class_size */
00277                         NULL,                      /* base_init */
00278                         NULL,                      /* base_destroy */
00279                         NULL,                      /* class_init */
00280                         NULL,                      /* class_destroy */
00281                         NULL,                      /* class_data */
00282                         0,                         /* instance_size */
00283                         0,                         /* n_preallocs */
00284                         NULL,                      /* instance_init */
00285                         &value_table               /* 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 }

Generated on Thu Feb 22 06:15:18 2007 for midgard-core by  doxygen 1.4.6