1use core::borrow::Borrow;
7use core::{fmt, hash};
8use core::cmp::Ordering;
9use core::ops::{Add, Sub};
10use oldtime::Duration as OldDuration;
11
12use {Weekday, Datelike};
13use offset::{TimeZone, Utc};
14use naive::{self, NaiveDate, NaiveTime, IsoWeek};
15use DateTime;
16#[cfg(any(feature = "alloc", feature = "std", test))]
17use format::{DelayedFormat, Item, StrftimeItems};
18
19#[derive(Clone)]
44pub struct Date<Tz: TimeZone> {
45 date: NaiveDate,
46 offset: Tz::Offset,
47}
48
49pub const MIN_DATE: Date<Utc> = Date { date: naive::MIN_DATE, offset: Utc };
51pub const MAX_DATE: Date<Utc> = Date { date: naive::MAX_DATE, offset: Utc };
53
54impl<Tz: TimeZone> Date<Tz> {
55 #[inline]
60 pub fn from_utc(date: NaiveDate, offset: Tz::Offset) -> Date<Tz> {
61 Date { date: date, offset: offset }
62 }
63
64 #[inline]
69 pub fn and_time(&self, time: NaiveTime) -> Option<DateTime<Tz>> {
70 let localdt = self.naive_local().and_time(time);
71 self.timezone().from_local_datetime(&localdt).single()
72 }
73
74 #[inline]
79 pub fn and_hms(&self, hour: u32, min: u32, sec: u32) -> DateTime<Tz> {
80 self.and_hms_opt(hour, min, sec).expect("invalid time")
81 }
82
83 #[inline]
88 pub fn and_hms_opt(&self, hour: u32, min: u32, sec: u32) -> Option<DateTime<Tz>> {
89 NaiveTime::from_hms_opt(hour, min, sec).and_then(|time| self.and_time(time))
90 }
91
92 #[inline]
98 pub fn and_hms_milli(&self, hour: u32, min: u32, sec: u32, milli: u32) -> DateTime<Tz> {
99 self.and_hms_milli_opt(hour, min, sec, milli).expect("invalid time")
100 }
101
102 #[inline]
108 pub fn and_hms_milli_opt(&self, hour: u32, min: u32, sec: u32,
109 milli: u32) -> Option<DateTime<Tz>> {
110 NaiveTime::from_hms_milli_opt(hour, min, sec, milli).and_then(|time| self.and_time(time))
111 }
112
113 #[inline]
119 pub fn and_hms_micro(&self, hour: u32, min: u32, sec: u32, micro: u32) -> DateTime<Tz> {
120 self.and_hms_micro_opt(hour, min, sec, micro).expect("invalid time")
121 }
122
123 #[inline]
129 pub fn and_hms_micro_opt(&self, hour: u32, min: u32, sec: u32,
130 micro: u32) -> Option<DateTime<Tz>> {
131 NaiveTime::from_hms_micro_opt(hour, min, sec, micro).and_then(|time| self.and_time(time))
132 }
133
134 #[inline]
140 pub fn and_hms_nano(&self, hour: u32, min: u32, sec: u32, nano: u32) -> DateTime<Tz> {
141 self.and_hms_nano_opt(hour, min, sec, nano).expect("invalid time")
142 }
143
144 #[inline]
150 pub fn and_hms_nano_opt(&self, hour: u32, min: u32, sec: u32,
151 nano: u32) -> Option<DateTime<Tz>> {
152 NaiveTime::from_hms_nano_opt(hour, min, sec, nano).and_then(|time| self.and_time(time))
153 }
154
155 #[inline]
159 pub fn succ(&self) -> Date<Tz> {
160 self.succ_opt().expect("out of bound")
161 }
162
163 #[inline]
167 pub fn succ_opt(&self) -> Option<Date<Tz>> {
168 self.date.succ_opt().map(|date| Date::from_utc(date, self.offset.clone()))
169 }
170
171 #[inline]
175 pub fn pred(&self) -> Date<Tz> {
176 self.pred_opt().expect("out of bound")
177 }
178
179 #[inline]
183 pub fn pred_opt(&self) -> Option<Date<Tz>> {
184 self.date.pred_opt().map(|date| Date::from_utc(date, self.offset.clone()))
185 }
186
187 #[inline]
189 pub fn offset(&self) -> &Tz::Offset {
190 &self.offset
191 }
192
193 #[inline]
195 pub fn timezone(&self) -> Tz {
196 TimeZone::from_offset(&self.offset)
197 }
198
199 #[inline]
202 pub fn with_timezone<Tz2: TimeZone>(&self, tz: &Tz2) -> Date<Tz2> {
203 tz.from_utc_date(&self.date)
204 }
205
206 #[inline]
210 pub fn checked_add_signed(self, rhs: OldDuration) -> Option<Date<Tz>> {
211 let date = try_opt!(self.date.checked_add_signed(rhs));
212 Some(Date { date: date, offset: self.offset })
213 }
214
215 #[inline]
219 pub fn checked_sub_signed(self, rhs: OldDuration) -> Option<Date<Tz>> {
220 let date = try_opt!(self.date.checked_sub_signed(rhs));
221 Some(Date { date: date, offset: self.offset })
222 }
223
224 #[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
230 #[inline]
231 pub fn signed_duration_since<Tz2: TimeZone>(self, rhs: Date<Tz2>) -> OldDuration {
232 self.date.signed_duration_since(rhs.date)
233 }
234
235 #[inline]
237 pub fn naive_utc(&self) -> NaiveDate {
238 self.date
239 }
240
241 #[inline]
247 pub fn naive_local(&self) -> NaiveDate {
248 self.date
249 }
250}
251
252fn map_local<Tz: TimeZone, F>(d: &Date<Tz>, mut f: F) -> Option<Date<Tz>>
254 where F: FnMut(NaiveDate) -> Option<NaiveDate> {
255 f(d.naive_local()).and_then(|date| d.timezone().from_local_date(&date).single())
256}
257
258impl<Tz: TimeZone> Date<Tz> where Tz::Offset: fmt::Display {
259 #[cfg(any(feature = "alloc", feature = "std", test))]
261 #[inline]
262 pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
263 where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>> {
264 DelayedFormat::new_with_offset(Some(self.naive_local()), None, &self.offset, items)
265 }
266
267 #[cfg(any(feature = "alloc", feature = "std", test))]
271 #[inline]
272 pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat<StrftimeItems<'a>> {
273 self.format_with_items(StrftimeItems::new(fmt))
274 }
275}
276
277impl<Tz: TimeZone> Datelike for Date<Tz> {
278 #[inline] fn year(&self) -> i32 { self.naive_local().year() }
279 #[inline] fn month(&self) -> u32 { self.naive_local().month() }
280 #[inline] fn month0(&self) -> u32 { self.naive_local().month0() }
281 #[inline] fn day(&self) -> u32 { self.naive_local().day() }
282 #[inline] fn day0(&self) -> u32 { self.naive_local().day0() }
283 #[inline] fn ordinal(&self) -> u32 { self.naive_local().ordinal() }
284 #[inline] fn ordinal0(&self) -> u32 { self.naive_local().ordinal0() }
285 #[inline] fn weekday(&self) -> Weekday { self.naive_local().weekday() }
286 #[inline] fn iso_week(&self) -> IsoWeek { self.naive_local().iso_week() }
287
288 #[inline]
289 fn with_year(&self, year: i32) -> Option<Date<Tz>> {
290 map_local(self, |date| date.with_year(year))
291 }
292
293 #[inline]
294 fn with_month(&self, month: u32) -> Option<Date<Tz>> {
295 map_local(self, |date| date.with_month(month))
296 }
297
298 #[inline]
299 fn with_month0(&self, month0: u32) -> Option<Date<Tz>> {
300 map_local(self, |date| date.with_month0(month0))
301 }
302
303 #[inline]
304 fn with_day(&self, day: u32) -> Option<Date<Tz>> {
305 map_local(self, |date| date.with_day(day))
306 }
307
308 #[inline]
309 fn with_day0(&self, day0: u32) -> Option<Date<Tz>> {
310 map_local(self, |date| date.with_day0(day0))
311 }
312
313 #[inline]
314 fn with_ordinal(&self, ordinal: u32) -> Option<Date<Tz>> {
315 map_local(self, |date| date.with_ordinal(ordinal))
316 }
317
318 #[inline]
319 fn with_ordinal0(&self, ordinal0: u32) -> Option<Date<Tz>> {
320 map_local(self, |date| date.with_ordinal0(ordinal0))
321 }
322}
323
324impl<Tz: TimeZone> Copy for Date<Tz> where <Tz as TimeZone>::Offset: Copy {}
326unsafe impl<Tz: TimeZone> Send for Date<Tz> where <Tz as TimeZone>::Offset: Send {}
327
328impl<Tz: TimeZone, Tz2: TimeZone> PartialEq<Date<Tz2>> for Date<Tz> {
329 fn eq(&self, other: &Date<Tz2>) -> bool { self.date == other.date }
330}
331
332impl<Tz: TimeZone> Eq for Date<Tz> {
333}
334
335impl<Tz: TimeZone> PartialOrd for Date<Tz> {
336 fn partial_cmp(&self, other: &Date<Tz>) -> Option<Ordering> {
337 self.date.partial_cmp(&other.date)
338 }
339}
340
341impl<Tz: TimeZone> Ord for Date<Tz> {
342 fn cmp(&self, other: &Date<Tz>) -> Ordering { self.date.cmp(&other.date) }
343}
344
345impl<Tz: TimeZone> hash::Hash for Date<Tz> {
346 fn hash<H: hash::Hasher>(&self, state: &mut H) { self.date.hash(state) }
347}
348
349impl<Tz: TimeZone> Add<OldDuration> for Date<Tz> {
350 type Output = Date<Tz>;
351
352 #[inline]
353 fn add(self, rhs: OldDuration) -> Date<Tz> {
354 self.checked_add_signed(rhs).expect("`Date + Duration` overflowed")
355 }
356}
357
358impl<Tz: TimeZone> Sub<OldDuration> for Date<Tz> {
359 type Output = Date<Tz>;
360
361 #[inline]
362 fn sub(self, rhs: OldDuration) -> Date<Tz> {
363 self.checked_sub_signed(rhs).expect("`Date - Duration` overflowed")
364 }
365}
366
367impl<Tz: TimeZone> Sub<Date<Tz>> for Date<Tz> {
368 type Output = OldDuration;
369
370 #[inline]
371 fn sub(self, rhs: Date<Tz>) -> OldDuration {
372 self.signed_duration_since(rhs)
373 }
374}
375
376impl<Tz: TimeZone> fmt::Debug for Date<Tz> {
377 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
378 write!(f, "{:?}{:?}", self.naive_local(), self.offset)
379 }
380}
381
382impl<Tz: TimeZone> fmt::Display for Date<Tz> where Tz::Offset: fmt::Display {
383 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
384 write!(f, "{}{}", self.naive_local(), self.offset)
385 }
386}
387