phobos/std/gregorian.d
2011-02-26 15:32:21 -06:00

419 lines
9.8 KiB
D

// Written in the D programming language.
/**
$(RED Scheduled for deprecation. Please use std.datetime instead.)
Macros:
WIKI = Phobos/StdGregorian
Copyright: Copyright Andrei Alexandrescu 2008 - 2009.
License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
Authors: $(WEB erdani.org, Andrei Alexandrescu)
Source: $(PHOBOSSRC std/_gregorian.d)
*/
/*
Copyright Andrei Alexandrescu 2010-.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt)
*/
module std.gregorian;
pragma(msg, "std.gregorian has been scheduled for deprecation. "
"Please use std.datetime instead.");
version(posix) import core.sys.posix.time;
import std.typecons;
import std.conv;
version(unittest) import std.stdio;
version(none) unittest
{
auto d = Date(2010, May, 1);
auto d1 = d;
assert(d.year == 2010);
assert(d.month == May);
assert(d.day == 1);
assert(d.dayOfWeek == 6);
assert(d.dayOfYear == 121);
assert(Date(2010, Jan, 5).dayOfYear == 5);
}
version(none) unittest
{
auto d1 = Date(negInfin);
auto d2 = Date(posInfin);
auto d3 = Date(notADateTime);
auto d4 = Date(maxDateTime);
auto d5 = Date(minDateTime);
}
version(none) unittest
{
auto d1 = fromString("2002-1-25");
auto d2 = fromUndelimitedString("20020125");
}
version(none) unittest
{
auto d1 = dayClockLocalDay();
auto d2 = dayClockUniversalDay();
}
alias ushort GregYear;
alias ushort GregMonth;
alias ushort GregDay;
alias uint GregDayOfWeek;
alias uint GregDayOfYear;
enum { Jan = 1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec }
// Special constants
struct Special { ulong value; }
static immutable
notADateTime = Special(0),
negInfin = Special(1),
posInfin = Special(2),
minDateTime = Special(3),
maxDateTime = Special(4),
notSpecial = Special(5);
struct Date
{
this(uint year, uint month, uint day)
{
immutable
a = cast(ushort)((14-month)/12),
y = cast(ushort)(year + 4800 - a),
m = cast(ushort)(month + 12*a - 3);
days_ = day + ((153*m + 2)/5) + 365*y + (y/4)
- (y/100) + (y/400) - 32045;
}
this(Special s)
{
}
// Accessors
@property GregYear year() const
{
immutable
a = days_ + 32044,
b = (4*a + 3)/146097,
c = a-((146097*b)/4),
d = (4*c + 3)/1461,
e = c - (1461*d)/4,
m = (5*e + 2)/153;
//auto day = cast(ushort) (e - ((153*m + 2)/5) + 1);
//auto month = cast(ushort) (m + 3 - 12 * (m/10));
immutable year = cast(ushort) (100*b + d - 4800 + (m/10));
return year;
}
@property GregMonth month() const
{
immutable
a = days_ + 32044,
b = (4*a + 3)/146097,
c = a-((146097*b)/4),
d = (4*c + 3)/1461,
e = c - (1461*d)/4,
m = (5*e + 2)/153;
//auto day = cast(ushort) (e - ((153*m + 2)/5) + 1);
immutable month = cast(ushort) (m + 3 - 12 * (m/10));
//auto year = cast(ushort) (100*b + d - 4800 + (m/10));
return month;
}
@property GregDay day() const
{
immutable
a = days_ + 32044,
b = (4*a + 3)/146097,
c = a-((146097*b)/4),
d = (4*c + 3)/1461,
e = c - (1461*d)/4,
m = (5*e + 2)/153,
day = cast(ushort) (e - ((153*m + 2)/5) + 1);
//auto month = cast(ushort) (m + 3 - 12 * (m/10));
//auto year = cast(ushort) (100*b + d - 4800 + (m/10));
return day;
}
@property Tuple!(GregYear, GregMonth, GregDay)
yearMonthDay() const
{
immutable
a = days_ + 32044,
b = (4*a + 3)/146097,
c = a-((146097*b)/4),
d = (4*c + 3)/1461,
e = c - (1461*d)/4,
m = (5*e + 2)/153;
auto day = cast(ushort) (e - ((153*m + 2)/5) + 1);
auto month = cast(ushort) (m + 3 - 12 * (m/10));
auto year = cast(ushort) (100*b + d - 4800 + (m/10));
return tuple(year, month, day);
}
@property GregDayOfWeek dayOfWeek() const
{
immutable
ymd = yearMonthDay,
a = cast(ushort) ((14-ymd._1)/12),
y = cast(ushort) (ymd._0 - a),
m = cast(ushort) (ymd._1 + 12*a - 2),
d = cast(ushort) ((ymd._2 + y + (y/4) - (y/100) +
(y/400) + (31*m)/12) % 7);
return d;
}
@property GregDayOfYear dayOfYear() const
{
const start_of_year = Date(year(), 1, 1);
auto doy = cast(ushort) ((this - start_of_year).days() + 1);
return cast(GregDayOfYear) doy;
}
@property Date endOfMonth() const
{
assert(0);
}
@property bool isInfinity() const
{
return isNegInfinity || isPosInfinity;
}
@property bool isNegInfinity() const
{
return days_ == negInfin.value;
}
@property bool isPosInfinity() const
{
return days_ == posInfin.value;
}
@property bool isNotADate() const
{
return days_ == notADateTime.value;
}
@property bool isSpecial() const
{
return isNotADate || isInfinity;
}
@property Special asSpecial() const
{
return days_ < notSpecial.value
? Special(days_)
: notSpecial;
}
@property long modJulianDay() const
{
auto ymd = yearMonthDay();
return julianDay(ymd) - 2400001; //prerounded
}
static @property long julianDay(Tuple!(ushort, ushort, ushort) ymd)
{
immutable
a = cast(ushort) ((14-ymd._1)/12),
y = cast(ushort) (ymd._0 + 4800 - a),
m = cast(ushort) (ymd._1 + 12*a - 3),
d = ymd._2 + ((153*m + 2)/5) + 365*y + (y/4) - (y/100)
+ (y/400) - 32045;
return d;
}
static bool isLeapYear(uint year)
{
//divisible by 4, not if divisible by 100, but true if
//divisible by 400
return (!(year % 4)) && ((year % 100) || (!(year % 400)));
}
@property int weekNumber() const
{
auto
ymd = yearMonthDay,
julianbegin = julianDay(tuple(cast(ushort)ymd._0,
cast(ushort)1, cast(ushort)1)),
juliantoday = julianDay(ymd);
long day = (julianbegin + 3) % 7;
ulong week = (juliantoday + day - julianbegin + 4)/7;
if ((week >= 1) && (week <= 52))
{
return cast(int) week;
}
if ((week == 53))
{
if((day==6) ||(day == 5 && isLeapYear(ymd._0)))
{
return cast(int) week; //under these circumstances week == 53.
}
else
{
return 1; //monday - wednesday is in week 1 of next year
}
}
//if the week is not in current year recalculate using the
//previous year as the beginning year
else
if (week == 0)
{
julianbegin = julianDay(
tuple(cast(ushort) (ymd._0 - 1), cast(ushort) 1,
cast(ushort) 1));
juliantoday = julianDay(ymd);
day = (julianbegin + 3) % 7;
week = (juliantoday + day - julianbegin + 4)/7;
return cast(int) week;
}
return cast(int) week; //not reachable -- well except if day == 5 and
//is_leap_year != true
}
@property uint endOfMonthDay() const
{
switch (month) {
case 2:
if (isLeapYear(year)) {
return 29;
} else {
return 28;
};
case 4:
case 6:
case 9:
case 11:
return 30;
default:
return 31;
}
}
@property string toSimpleString() const
{
auto ymd = yearMonthDay;
return text(ymd._0, '-', ymd._1, '-', ymd._2);
}
@property string toIsoString() const
{
assert(0);
}
@property string toIsoExtendedString() const
{
assert(0);
}
bool opEquals(ref const Date rhs) const
{
return days_ == rhs.days_;
}
int opCmp(in Date rhs) const
{
return days_ < rhs.days_ ? -1 : days_ > rhs.days_ ? 1 : 0;
}
// Date opBinary(string op)(const Date d) const
// if (op == "-")
// {
// }
Days opBinary(string op)(const Date d) const
if (op == "-")
{
if (!isSpecial && !d.isSpecial)
{
return Days(days_ - d.days_);
}
else
{
assert(0);
}
}
static if (is(tm))
{
tm toTm()
{
assert(0);
}
}
private ulong days_;
}
struct Days
{
private long days_;
this(long d) { days_ = d; }
this(Special s) { }
@property long days() const { return days_; }
@property bool isNegative() const { return days_ < 0; }
@property static Days unit() { return Days(1); }
@property bool isSpecial()
{
assert(0);
}
bool opEquals(ref const Days rhs) const
{
return days_ == rhs.days_;
}
int opCmp(in Days rhs) const
{
return days_ < rhs.days_ ? -1 : days_ > rhs.days_ ? 1 : 0;
}
Days opBinary(string op)(Days d) const
if (op == "+" || op == "-")
{
}
}
Date fromString(in char[] s)
{
Date result;
return result;
}
Date fromUndelimitedString(in char[] s)
{
Date result;
return result;
}
Date dayClockLocalDay()
{
Date result;
return result;
}
Date dayClockUniversalDay()
{
Date result;
return result;
}
static if (is(tm))
{
Date dateFromTm(tm)
{
assert(0);
}
}