/src/libreoffice/include/tools/date.hxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | #pragma once |
20 | | |
21 | | #include <tools/toolsdllapi.h> |
22 | | |
23 | | #include <cstdlib> |
24 | | #include <ostream> |
25 | | |
26 | | #include <com/sun/star/util/Date.hpp> |
27 | | |
28 | | namespace com::sun::star::util { struct DateTime; } |
29 | | |
30 | | enum DayOfWeek { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, |
31 | | SATURDAY, SUNDAY }; |
32 | | |
33 | | /** Represents a date in the proleptic Gregorian calendar. |
34 | | |
35 | | Largest representable date is 32767-12-31 = 327671231 |
36 | | |
37 | | Smallest representable date is -32768-01-01 = -327680101 |
38 | | |
39 | | Due to possible conversions to css::util::Date, which has a short |
40 | | Year member variable, these limits are fix. |
41 | | |
42 | | Year value 0 is unused. The year before year 1 CE is year 1 BCE, which is |
43 | | the traditional proleptic Gregorian calendar. |
44 | | |
45 | | This is not how ISO 8601:2000 defines things (but ISO 8601:1998 Draft |
46 | | Revision did), but it enables class Date to be used for writing XML files |
47 | | as XML Schema Part 2 in D.3.2 No Year Zero says |
48 | | "The year "0000" is an illegal year value.", see |
49 | | https://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#noYearZero |
50 | | and furthermore the note for 3.2.7 dateTime |
51 | | https://www.w3.org/TR/2004/REC-xmlschema-2-20041028/#dateTime |
52 | | |
53 | | */ |
54 | | class SAL_WARN_UNUSED TOOLS_DLLPUBLIC Date |
55 | | { |
56 | | private: |
57 | | sal_Int32 mnDate; |
58 | | void setDateFromDMY( sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear ); |
59 | | |
60 | | public: |
61 | | enum DateInitSystem |
62 | | { |
63 | | SYSTEM |
64 | | }; |
65 | | |
66 | | enum DateInitEmpty |
67 | | { |
68 | | EMPTY |
69 | | }; |
70 | | |
71 | 6.74M | explicit Date( DateInitEmpty ) : mnDate(0) {} |
72 | | explicit Date( DateInitSystem ); |
73 | 6.90M | explicit Date( sal_Int32 nDate ) : mnDate(nDate) {} |
74 | 4.16M | Date( const Date& rDate ) : mnDate(rDate.mnDate) {} |
75 | | |
76 | | /** nDay and nMonth both must be <100, nYear must be != 0 */ |
77 | | Date( sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear ) |
78 | 1.44M | { setDateFromDMY(nDay, nMonth, nYear); } |
79 | | |
80 | | explicit Date( const css::util::Date& rUDate ) |
81 | 63.6k | { |
82 | 63.6k | setDateFromDMY(rUDate.Day, rUDate.Month, rUDate.Year); |
83 | 63.6k | } |
84 | | explicit Date( const css::util::DateTime& _rDateTime ); |
85 | | |
86 | 0 | bool IsEmpty() const { return mnDate == 0; } |
87 | | |
88 | | void SetDate( sal_Int32 nNewDate ); |
89 | 1.04M | sal_Int32 GetDate() const { return mnDate; } |
90 | | /** Type safe access for values that are guaranteed to be unsigned, like Date::SYSTEM. */ |
91 | 87.0k | sal_uInt32 GetDateUnsigned() const { return std::abs(mnDate); } |
92 | 0 | css::util::Date GetUNODate() const { return css::util::Date(GetDay(), GetMonth(), GetYear()); } |
93 | | |
94 | | /** nNewDay must be <100 */ |
95 | | void SetDay( sal_uInt16 nNewDay ); |
96 | | /** nNewMonth must be <100 */ |
97 | | void SetMonth( sal_uInt16 nNewMonth ); |
98 | | /** nNewYear must be != 0 */ |
99 | | void SetYear( sal_Int16 nNewYear ); |
100 | | |
101 | 2.10M | sal_uInt16 GetDay() const { return std::abs(mnDate) % 100; } |
102 | 2.10M | sal_uInt16 GetMonth() const { return (std::abs(mnDate) / 100) % 100; } |
103 | 2.32M | sal_Int16 GetYear() const { return mnDate / 10000; } |
104 | | /** Type safe access for values that are guaranteed to be unsigned, like Date::SYSTEM. */ |
105 | 0 | sal_uInt16 GetYearUnsigned() const { return std::abs(GetYear()); } |
106 | 0 | sal_Int16 GetNextYear() const { sal_Int16 nY = GetYear(); return nY == -1 ? 1 : nY + 1; } |
107 | 0 | sal_Int16 GetPrevYear() const { sal_Int16 nY = GetYear(); return nY == 1 ? -1 : nY - 1; } |
108 | | |
109 | | /** Add years skipping year 0 and truncating at limits. If the original |
110 | | date was on Feb-29 and the resulting date is not a leap year, the |
111 | | result is adjusted to Feb-28. |
112 | | */ |
113 | | void AddYears( sal_Int16 nAddYears ); |
114 | | |
115 | | /** Add months skipping year 0 and truncating at limits. If the original |
116 | | date was on Feb-29 or day 31 and the resulting date is not a leap year |
117 | | or a month with fewer days, the result is adjusted to Feb-28 or day 30. |
118 | | */ |
119 | | void AddMonths( sal_Int32 nAddMonths ); |
120 | | |
121 | | /** Add days skipping year 0 and truncating at limits. |
122 | | */ |
123 | | void AddDays( sal_Int32 nAddDays ); |
124 | | |
125 | | // Same as AddDays, but returns false on int overflow cases |
126 | | [[nodiscard]] bool CheckedAddDays(sal_Int32 nAddDays); |
127 | | |
128 | | /** Obtain the day of the week for the date. |
129 | | |
130 | | Internally normalizes a copy of values. |
131 | | The result may be unexpected for a non-normalized invalid date like |
132 | | Date(31,11,2000) or a sequence of aDate.SetDay(31); aDate.SetMonth(11); |
133 | | */ |
134 | | DayOfWeek GetDayOfWeek() const; |
135 | | |
136 | | /** Obtain the day of the year for the date. |
137 | | |
138 | | Internally normalizes a copy of values. |
139 | | The result may be unexpected for a non-normalized invalid date like |
140 | | Date(31,11,2000) or a sequence of aDate.SetDay(31); aDate.SetMonth(11); |
141 | | */ |
142 | | sal_uInt16 GetDayOfYear() const; |
143 | | |
144 | | /** Obtain the week of the year for a date. |
145 | | |
146 | | @param nMinimumNumberOfDaysInWeek |
147 | | How many days of a week must reside in the first week of a year. |
148 | | |
149 | | Internally normalizes a copy of values. |
150 | | The result may be unexpected for a non-normalized invalid date like |
151 | | Date(31,11,2000) or a sequence of aDate.SetDay(31); aDate.SetMonth(11); |
152 | | */ |
153 | | sal_uInt16 GetWeekOfYear( DayOfWeek eStartDay = MONDAY, |
154 | | sal_Int16 nMinimumNumberOfDaysInWeek = 4 ) const; |
155 | | |
156 | | /** Obtain the number of days in the month of the year of the date. |
157 | | |
158 | | Internally normalizes a copy of values. |
159 | | |
160 | | The result may be unexpected for a non-normalized invalid date like |
161 | | Date(31,11,2000) or a sequence of aDate.SetDay(31); aDate.SetMonth(11); |
162 | | |
163 | | These would result in 31 as --11-31 rolls over to --12-01 and the |
164 | | number of days in December is returned. |
165 | | |
166 | | Instead, to obtain the value for the actual set use the static method |
167 | | Date::GetDaysInMonth( aDate.GetMonth(), aDate.GetYear()) in such cases. |
168 | | */ |
169 | | sal_uInt16 GetDaysInMonth() const; |
170 | | |
171 | 0 | sal_uInt16 GetDaysInYear() const { return (IsLeapYear()) ? 366 : 365; } |
172 | | bool IsLeapYear() const; |
173 | | |
174 | | /** If the represented date is valid (1<=month<=12, 1<=day<=(28,29,30,31) |
175 | | depending on month/year) AND is of the Gregorian calendar (1582-10-15 |
176 | | <= date) |
177 | | */ |
178 | | bool IsValidAndGregorian() const; |
179 | | |
180 | | /** If the represented date is valid (1<=month<=12, 1<=day<=(28,29,30,31) |
181 | | depending on month/year) */ |
182 | | bool IsValidDate() const; |
183 | | |
184 | | // Returns true, if the date is the end of the month, false otherwise. |
185 | | bool IsEndOfMonth() const; |
186 | | |
187 | | /** Normalize date, invalid day or month values are adapted such that they |
188 | | carry over to the next month or/and year, for example 1999-02-32 |
189 | | becomes 1999-03-04, 1999-13-01 becomes 2000-01-01, 1999-13-42 becomes |
190 | | 2000-02-11. Truncates at -32768-01-01 or 32767-12-31, 0001-00-x will |
191 | | yield the normalized value of -0001-12-x |
192 | | |
193 | | This may be necessary after Date ctors or if the SetDate(), SetDay(), |
194 | | SetMonth(), SetYear() methods set individual non-matching values. |
195 | | Adding/subtracting to/from dates never produces invalid dates. |
196 | | */ |
197 | | void Normalize(); |
198 | | |
199 | | bool IsBetween( const Date& rFrom, const Date& rTo ) const |
200 | 0 | { return ((mnDate >= rFrom.mnDate) && |
201 | 0 | (mnDate <= rTo.mnDate)); } |
202 | | |
203 | 0 | auto operator <=> ( const Date& rDate ) const = default; |
204 | | |
205 | | Date& operator =( const Date& rDate ) |
206 | 7.20M | { mnDate = rDate.mnDate; return *this; } |
207 | | Date& operator =( const css::util::Date& rUDate ) |
208 | 0 | { setDateFromDMY( rUDate.Day, rUDate.Month, rUDate.Year); return *this; } |
209 | | Date& operator ++(); |
210 | | Date& operator --(); |
211 | | |
212 | | TOOLS_DLLPUBLIC friend Date operator +( const Date& rDate, sal_Int32 nDays ); |
213 | | TOOLS_DLLPUBLIC friend Date operator -( const Date& rDate, sal_Int32 nDays ); |
214 | | TOOLS_DLLPUBLIC friend sal_Int32 operator -( const Date& rDate1, const Date& rDate2 ); |
215 | | |
216 | | /** Obtain number of days in a month of a year. |
217 | | |
218 | | Internally sanitizes nMonth to values 1 <= nMonth <= 12, does not |
219 | | normalize values. |
220 | | */ |
221 | | static sal_uInt16 GetDaysInMonth( sal_uInt16 nMonth, sal_Int16 nYear ); |
222 | | |
223 | | /// Internally normalizes values. |
224 | | static sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear ); |
225 | | /// Semantically identical to IsValidDate() member method. |
226 | | static bool IsValidDate( sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear ); |
227 | | /// Semantically identical to IsEndOfMonth() member method. |
228 | | static bool IsEndOfMonth(sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear); |
229 | | /// Semantically identical to Normalize() member method. |
230 | | static bool Normalize( sal_uInt16 & rDay, sal_uInt16 & rMonth, sal_Int16 & rYear ); |
231 | | |
232 | | /// An accelerated form of DateToDays on this date |
233 | | sal_Int32 GetAsNormalizedDays() const; |
234 | | }; |
235 | | |
236 | | TOOLS_DLLPUBLIC std::ostream& operator<<(std::ostream& os, const Date& rDate); |
237 | | |
238 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |