view src/core/date.cc @ 319:d928ec7b6a0d

services/kitsu: implement GetAnimeList() it finally works!
author Paper <paper@paper.us.eu.org>
date Wed, 12 Jun 2024 17:52:26 -0400
parents b1f4d1867ab1
children
line wrap: on
line source

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

#include <QDate>
#include <QDebug>

#include <algorithm>
#include <cstdio>

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

Date::Date() {
}

Date::Date(Date::Year y) {
	SetYear(y);
}

Date::Date(Date::Year y, Date::Month m, Date::Day d) {
	SetYear(y);
	SetMonth(m);
	SetDay(d);
}

Date::Date(const std::string& str) {
	unsigned int y, m, d;

	/* I don't like this that much, but it works... */
	int amt = std::sscanf(str.c_str(), "%4u-%2u-%2u", &y, &m, &d);

	if (amt > 0)
		SetYear(y);

	if (amt > 1)
		SetMonth(static_cast<Date::Month>(m - 1));

	if (amt > 2)
		SetDay(d);
}

Date::Date(const QDate& date) {
	SetYear(date.year());
	auto m = date.month();
	m = std::clamp(m, static_cast<decltype(m)>(Date::Month::Jan), static_cast<decltype(m)>(Date::Month::Dec));
	SetMonth(static_cast<Date::Month>(m));
	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_pointer) && json.at("/year"_json_pointer).is_number())
		SetYear(json.at("/year"_json_pointer).get<unsigned int>());

	if (json.contains("/month"_json_pointer) && json.at("/month"_json_pointer).is_number()) {
		auto m = json.at("/month"_json_pointer).get<unsigned int>();
		m = std::clamp(m, static_cast<decltype(m)>(Date::Month::Jan), static_cast<decltype(m)>(Date::Month::Dec));
		SetMonth(static_cast<Date::Month>(m));
	}

	if (json.contains("/day"_json_pointer) && json.at("/day"_json_pointer).is_number())
		SetDay(json.at("/day"_json_pointer).get<unsigned char>());
}

Date::Date(Time::Timestamp timestamp) {
	Date(QDateTime::fromSecsSinceEpoch(timestamp).date());
}

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

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

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

void Date::SetYear(Date::Year y) {
	year.emplace(y);
}

void Date::SetMonth(Date::Month m) {
	month.emplace(m);
}

void Date::SetDay(Date::Day d) {
	day.emplace(std::clamp(d, static_cast<Date::Day>(1U), static_cast<Date::Day>(31U)));
}

std::optional<Date::Year> Date::GetYear() const {
	return year;
}

std::optional<Date::Month> Date::GetMonth() const {
	return month;
}

std::optional<Date::Day> Date::GetDay() const {
	return day;
}

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

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), static_cast<unsigned int>(month.value_or(Date::Month::Jan)), day.value_or(1));
}

nlohmann::json Date::GetAsAniListJson() const {
	nlohmann::json json = {
	    {"year",  nullptr},
        {"month", nullptr},
        {"day",   nullptr}
    };

	if (year)
		json["year"] = static_cast<unsigned int>(year.value());

	if (month)
		json["month"] = static_cast<unsigned char>(month.value());

	if (day)
		json["day"] = static_cast<unsigned char>(day.value());

	return json;
}