00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 #include "math/time.hpp"
00035 #include "data/string.hpp"
00036 #include "data/exception.hpp"
00037 
00038 #include <cmath>
00039 #include <cwchar>
00040 
00041 namespace gsgl
00042 {
00043 
00044     namespace math
00045     {
00046         const double julian_day::J1970 = 2440587.5; 
00047         const double julian_day::JDAY  = 86400.0;   
00048         
00049 
00050         julian_day::julian_day()
00051             : math_object(), jdn(0)
00052         {
00053         } 
00054 
00055 
00056         julian_day::julian_day(const double & jdn)
00057             : math_object(), jdn(jdn)
00058         {
00059         } 
00060 
00061 
00062         julian_day::julian_day(const time_t & t)
00063             : math_object(), jdn( J1970 + static_cast<double>(t) / JDAY )
00064         {
00065         } 
00066 
00067 
00068         time_t julian_day::to_time_t() const
00069         {
00070             return static_cast<time_t>( (jdn - J1970) * JDAY );
00071         } 
00072 
00073 
00074         
00075 
00076         struct info
00077         {
00078             int year, month, day;
00079             int hour, minute, second;
00080         }; 
00081 
00082         static void jdn2info(const double jdn, info & i)
00083         {
00084             double jdd = jdn + 0.5;
00085             double Z;
00086             double F = ::modf(jdd, &Z);
00087 
00088             double A;
00089 
00090             if (Z < 2299161.0)
00091             {
00092                 A = Z;
00093             }
00094             else
00095             {
00096                 double a = ::floor( (Z - 1867216.25) / 36524.25 );
00097                 A = Z + 1.0 + a - ::floor(a/4.0);
00098             }
00099 
00100             double B = A + 1524.0;
00101             double C = ::floor( (B - 122.1) / 365.25 );
00102             double D = ::floor( 365.25 * C );
00103             double E = ::floor( (B - D) / 30.6001 );
00104 
00105             double day = B - D - ::floor(30.6001 * E) + F;
00106             double month = (E < 14.0) ? E - 1.0 : E - 13.0;
00107             double year = (month > 2.0) ? C - 4716.0 : C - 4715;
00108 
00109             double day_i;
00110             double day_f = ::modf(day, &day_i);
00111             
00112             i.year = static_cast<int>(year);
00113             i.month = static_cast<int>(month);
00114             i.day = static_cast<int>(day_i);
00115 
00116             double hours = day_f * 24.0;
00117             double hours_i;
00118             double hours_f = ::modf(hours, &hours_i);
00119 
00120             double minutes = hours_f * 60.0;
00121             double minutes_i;
00122             double minutes_f = ::modf(minutes, &minutes_i);
00123 
00124             double seconds = minutes_f * 60.0;
00125 
00126             i.hour = static_cast<int>(hours_i);
00127             i.minute = static_cast<int>(minutes_i);
00128             i.second = static_cast<int>(::floor(seconds));
00129         } 
00130 
00131         static double info2jdn(const info & i)
00132         {
00133             double t = static_cast<double>(i.hour) * 3600.0 
00134                 + static_cast<double>(i.minute) * 60.0 
00135                 + static_cast<double>(i.second);
00136             double Y = static_cast<double>(i.year);
00137             double M = static_cast<double>(i.month);
00138             double D = static_cast<double>(i.day) + t/julian_day::JDAY;
00139 
00140             if (M <= 2.0)
00141             {
00142                 Y -= 1.0;
00143                 M += 12.0;
00144             }
00145 
00146             double A = ::floor(Y/100.0);
00147             double B = 2.0 - A + ::floor(A/4.0);
00148 
00149             double jdn = ::floor(365.25 * (Y + 4716.0)) + ::floor(30.6001 * (M + 1.0)) + D + B - 1524.5;
00150 
00151             return jdn;
00152         } 
00153 
00154 
00155         string julian_day::to_gregorian_string() const
00156         {
00157             info i;
00158             jdn2info(jdn, i);
00159 
00160             return string::format(L"%04d-%02d-%02d %02d:%02d:%02d", i.year, i.month, i.day, i.hour, i.minute, i.second);
00161         } 
00162 
00163 
00164         void julian_day::from_gregorian_string(const string & s)
00165         {
00166             info i;
00167 
00168             int num = ::swscanf(s.w_string(), L"%d-%d-%d %d:%d:%d", &i.year, &i.month, &i.day, &i.hour, &i.minute, &i.second);
00169 
00170             if (num != 6)
00171                 throw runtime_exception(L"Invalid datetime string.");
00172 
00173             if (i.month < 1 || i.month > 12)
00174                 throw runtime_exception(L"Invalid month value %d in datetime string.", i.month);
00175 
00176             if (i.day < 1 || i.day > 31)
00177                 throw runtime_exception(L"Invalid day value %d in datetime string.", i.day);
00178 
00179             if (i.hour < 0 || i.hour > 23)
00180                 throw runtime_exception(L"Invalid hour value %d in datetime string.", i.hour);
00181 
00182             if (i.minute < 0 || i.minute > 59)
00183                 throw runtime_exception(L"Invalid minute value %d in datetime string.", i.minute);
00184 
00185             if (i.second < 0 || i.second > 59)
00186                 throw runtime_exception(L"Invalid second value %d in datetime string.", i.second);
00187 
00188             jdn = info2jdn(i);
00189         } 
00190 
00191 
00192         julian_day julian_day::now()
00193         {
00194             return julian_day(::time(0));
00195         } 
00196 
00197     } 
00198 
00199 }