This is a Date class I made for a hobby project. It does not deal with time at all; that is, the smallest unit of time it considers is one day, and no concern with time zones.
Where I do most of my coding, I'm not allowed C++11, so if there are any new languages features that would apply here, I am definitely interested in hearing about it. I'd also like to hear about the overall design of the class, or any edge cases I may have missed.
Date.h
#pragma once
#include <memory>
#include <string>
#include <vector>
#include <time.h>
/**
* Represents a date. Does not account for time. Does not account for time zones
*/
class Date
{
public:
/**
* @brief Construct current, local Date
*/
Date();
/**
* @brief Construct local Date from timestamp
* @param timestamp seconds since January 1 1970 UTC
*/
Date(time_t timestamp);
/**
* Return the year
*/
size_t getYear() const;
/**
* @brief Return a number representing the month.
*
* @return represented month
*/
size_t getMonth() const;
/**
* @brief get name of month, in English
*/
std::string getMonthString() const;
/**
* @brief get day of month
*/
size_t getDate() const;
/**
* @brief Increment current date by given number of years.
*/
void addYears(int numberOfYears);
/**
* @brief Increment current date by given number of months.
*/
void addMonths(int numberOfMonths);
/**
* @brief Increment current date by given number of days.
*/
void addDays(int numberOfDays);
/**
* @brief return String representation of date
* example: 1 February 1983
*/
std::string toString() const;
bool operator==(const Date& rhs) const;
bool operator!=(const Date& rhs) const;
private:
bool isLeapYear(size_t year) const;
bool isLeapYear() const;
void init(time_t timestamp);
const static std::vector<std::string> monthNames;
size_t daysPerMonth() const;
int date;
int month;
int year;
};
std::ostream& operator<<(std::ostream& stream, const Date& rhs);
Date.cpp
#include "stdafx.h"
#include "Date.h"
#include <cassert>
#include <vector>
Date::Date()
{
init(time(NULL));
}
Date::Date(time_t timestamp)
{
init(timestamp);
}
void Date::init(time_t timestamp)
{
struct tm datetime;
localtime_s(&datetime, ×tamp);
year = datetime.tm_year + 1900;
month = datetime.tm_mon;
date = datetime.tm_mday;
}
size_t Date::getYear() const
{
return year;
}
size_t Date::getMonth() const
{
//1-index for human use
return month + 1;
}
size_t Date::getDate() const
{
return date;
}
std::string Date::toString() const
{
return std::to_string(getDate()) + " " + getMonthString() + " " + std::to_string(getYear());
}
const std::vector<std::string> Date::monthNames = {
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
};
std::string Date::getMonthString() const
{
return monthNames[getMonth()];
}
bool Date::operator==(const Date& rhs) const
{
return getYear() == rhs.getYear() &&
getMonth() == rhs.getMonth() &&
getDate() == rhs.getDate();
}
bool Date::operator!=(const Date& rhs) const
{
return !(*this == rhs);
}
std::ostream& operator<<(std::ostream& stream, const Date& rhs)
{
return stream << rhs.toString();
}
void Date::addYears(int numberOfYears)
{
if (isLeapYear() &&
!isLeapYear(getYear() + numberOfYears) &&
date == 29)
{
addDays(1);
}
year += numberOfYears;
}
void Date::addDays(int numberOfDays)
{
numberOfDays += (date - 1);
date = 1;
while (numberOfDays < 0)
{
addMonths(-1);
numberOfDays += daysPerMonth();
}
while (numberOfDays >= daysPerMonth())
{
numberOfDays -= daysPerMonth();
addMonths(1);
}
date += numberOfDays;
}
void Date::addMonths(int numberOfMonths)
{
month += numberOfMonths;
while (month < 0)
{
addYears(-1);
month += 12;
}
while (month > 11)
{
addYears(1);
month -= 12;
}
if (date > daysPerMonth())
{
// No need to be precise. Just loop to the 1st.
month += 1;
date = 1;
}
}
size_t Date::daysPerMonth() const
{
assert(month >= 0);
assert(month <= 11);
switch (month)
{
case 0:
case 2:
case 4:
case 6:
case 7:
case 9:
case 11:
return 31;
case 3:
case 5:
case 8:
return 30;
default: //February
if (isLeapYear())
{
return 29;
}
return 28;
}
}
bool Date::isLeapYear(size_t year) const
{
return year % 4 == 0;
}
bool Date::isLeapYear() const
{
return isLeapYear(getYear());
}