view src/core/date.cc @ 196:f0ff06a45c42

date: use std::optional for values
author Paper <mrpapersonic@gmail.com>
date Thu, 07 Dec 2023 16:28:11 -0500
parents 9613d72b097e
children c4ca035c565d
line wrap: on
line source

#include "core/date.h"
#include "core/json.h"

#include <QDate>
#include <QDebug>

#include <algorithm>

/* An implementation of AniList's "fuzzy date" */

template<typename T>
bool CLAMP(T x, T low, T high) {
	return std::max(low, std::min(high, x));
}

Date::Date() {
}

Date::Date(unsigned int y) {
	SetYear(y);
}

Date::Date(unsigned int y, unsigned int m, unsigned int d) {
	SetYear(y);
	SetMonth(m);
	SetDay(d);
}

Date::Date(const QDate& date) {
	SetYear(date.year());
	SetMonth(date.month());
	SetDay(date.day());
}

Date::Date(const nlohmann::json& json) {
	/* NOTE: this constructor is made for use with
	   AniList FuzzyDate-style JSON. In the future, some other
	   methods may be parsed and whatnot if necessary. */
	if (json.contains("year") && json.at("year").is_number())
		SetYear(json.at("year").get<unsigned int>());
	if (json.contains("month") && json.at("month").is_number())
		SetMonth(json.at("month").get<unsigned int>());
	if (json.contains("day") && json.at("day").is_number())
		SetDay(json.at("day").get<unsigned int>());
}

void Date::VoidYear() {
	year.reset();
}

void Date::VoidMonth() {
	month.reset();
}

void Date::VoidDay() {
	day.reset();
}

void Date::SetYear(unsigned int y) {
	year = y;
}

void Date::SetMonth(unsigned int m) {
	month = CLAMP(m, 1U, 12U);
}

void Date::SetDay(unsigned int d) {
	day = CLAMP(d, 1U, 31U);
}

unsigned int Date::GetYear() const {
	return year.value_or(-1);
}

unsigned int Date::GetMonth() const {
	return month.value_or(-1);
}

unsigned int Date::GetDay() const {
	return day.value_or(-1);
}

bool Date::IsValid() const {
	return year.has_value() && month.has_value() && day.has_value();
}

bool Date::operator<(const Date& other) const {
	const unsigned int y = GetYear(), m = GetMonth(), d = GetDay();
	const unsigned int o_y = other.GetYear(), o_m = other.GetMonth(), o_d = other.GetDay();

	return (y < o_y && m < o_m && d < o_d);
}

bool Date::operator>(const Date& other) const {
	return other < (*this);
}

bool Date::operator<=(const Date& other) const {
	return !((*this) > other);
}

bool Date::operator>=(const Date& other) const {
	return !((*this) < other);
}

QDate Date::GetAsQDate() const {
	/* QDate doesn't support "missing" values (for good reason),
	 * so we do our best and return what we can.
	*/

	return QDate(year.value_or(2000), month.value_or(1), day.value_or(1));
}

nlohmann::json Date::GetAsAniListJson() const {
	nlohmann::json result = {};

	if (year.has_value())
		result["year"] = year.value();
	else
		result["year"] = nullptr;

	if (month.has_value())
		result["month"] = month.value();
	else
		result["month"] = nullptr;

	if (day.has_value())
		result["day"] = day.value();
	else
		result["day"] = nullptr;

	return result;
}