Added a few unittests + bugfix in Year
[libdatetime.git] / src / Date.cxx
bloba43207a56f2aef9e99e1dcc8437b6929117777a1
1 /*{{{ LICENCE
3 * libdatetime
4 * Copyright (C) 2009 Andreas Waidler <arandes@programmers.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED AS IS AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *}}}*/
20 #include <libdatetime/Date.hxx>
22 #include <libdatetime/Timestamp.hxx>
23 #include <libdatetime/Month.hxx>
24 #include <libdatetime/Year.hxx>
26 namespace libdatetime
28 Date::Date(const Timestamp& timestamp)/*{{{*/
29 : _timestamp(timestamp)
30 , _year(1970)
31 , _month(Month::January, _year.isLeapYear())
32 , _day(1)
34 if (_timestamp < Timestamp(0)) {
35 _calculatePreEpoch();
36 } else if (_timestamp > 0) {
37 _calculatePostEpoch();
41 /*}}}*/
42 const Year& Date::year() const/*{{{*/
44 return _year;
47 /*}}}*/
48 const Month& Date::month() const/*{{{*/
50 return _month;
53 /*}}}*/
54 int Date::day() const/*{{{*/
56 return _day;
59 /*}}}*/
60 Date::operator int() const/*{{{*/
62 return _timestamp;
65 /*}}}*/
66 void Date::incrementYear()/*{{{*/
68 ++_year;
71 /*}}}*/
72 void Date::decrementYear()/*{{{*/
74 --_year;
77 /*}}}*/
78 void Date::incrementMonth()/*{{{*/
80 // We can't blindly increment the month since the year changes after
81 // december.
82 // This is scenario does only occur if the Epoch does not begin in
83 // january.
84 if (_month == Month::December) {
85 ++_year;
86 _month = Month(Month::January, _year.isLeapYear());
87 } else {
88 ++_month;
92 /*}}}*/
93 void Date::decrementMonth()/*{{{*/
95 // See incrementMonth() for explanation.
96 if (_month == Month::January) {
97 --_year;
98 _month = Month(Month::December, _year.isLeapYear());
99 } else {
100 --_month;
104 /*}}}*/
105 void Date::incrementDay()/*{{{*/
107 // The month has to be incremented if the last day of the month is
108 // reached and shall be incremented. This happens only when the Epoch
109 // does not start on the first of any month.
110 if (_month.days() == _day) {
111 incrementMonth();
112 _day = 1;
113 } else {
114 ++_day;
118 /*}}}*/
119 void Date::decrementDay()/*{{{*/
121 // See incrementDay() for explanation.
122 if (1 == _day) {
123 decrementMonth();
124 _day = _month.days();
125 } else {
126 --_day;
130 /*}}}*/
131 void Date::_calculatePreEpoch()/*{{{*/
133 unsigned int remainder = 0 - _timestamp;
135 // As long as there is at least the same amount of seconds remaining than
136 // this previous year had, substract the seconds of that year from the
137 // remainder and decrease the year number.
139 while (true) {
140 decrementYear();
141 if (remainder < _year.seconds()) {
142 incrementYear();
143 break;
145 remainder -= _year.seconds();
148 // Calculate the month.
149 while (true) {
150 decrementMonth();
151 if (remainder < _month.seconds()) {
152 incrementMonth();
153 break;
155 remainder -= _month.seconds();
158 // Calculate the day of the month.
159 while (remainder >= 24 * 60 * 60) {
160 remainder -= 24 * 60 * 60;
161 decrementDay();
164 if (0 == remainder) return;
166 // We have a day. But if there is at least one second left to substract,
167 // the day has to be decremented as the time of the days is 00:00.
168 decrementDay();
169 _timestamp -= 24 * 60 * 60;
171 // We have to substract the time from the initial timestamp to obtain the
172 // actual timestamp of this date.
173 _timestamp += remainder;
176 /*}}}*/
177 void Date::_calculatePostEpoch()/*{{{*/
179 unsigned int remainder = _timestamp;
180 // Calculate the year. Note that it can also be altered in the loops below
181 // this one.
183 // As long as there is at least the same amount of seconds remaining than
184 // this current year has, substract the seconds of this year from the
185 // remainder and adjust the year.
186 while (remainder >= _year.seconds()) {
187 remainder -= _year.seconds();
188 incrementYear();
191 // Calculate the month.
192 while (remainder >= _month.seconds()) {
193 remainder -= _month.seconds();
194 incrementMonth();
197 // Calculate the day of the month.
198 while (remainder >= 24 * 60 * 60) {
199 remainder -= 24 * 60 * 60;
200 incrementDay();
203 // The Date has been calculated. What remains are the seconds that have
204 // passed since 00:00 this day, aka "the time". We have to substract the
205 // time from the initial timestamp to obtain the actual timestamp of this
206 // date.
207 _timestamp -= remainder;
210 /*}}}*/
213 // Use no tabs at all; two spaces indentation; max. eighty chars per line.
214 // vim: et ts=2 sw=2 sts=2 tw=80 fdm=marker