PDA

Просмотр полной версии : [Вопрос] Количество дней между датами



PawnoNoob
20.12.2017, 18:46
Приветствую. Появился один интересный вопрос: как получить количество дней между определёнными датами (например, между 01.01.2017 и 01.01.2018). Использую систему unix-времени.:hang1:

DeimoS
20.12.2017, 18:50
Ну переводи в unix, отнимай большую дату от меньшей и переводи обратно в формат даты.

PawnoNoob
20.12.2017, 19:03
Ну переводи в unix, отнимай большую дату от меньшей и переводи обратно в формат даты.

Шот сложно :sorry::blush2:

MARVEL
20.12.2017, 20:15
Шот сложно :sorry::blush2:

(1514764800 - 1483228800) / 86400 = 365
1514764800 - 01.01.2018
1483228800 - 01.01.2017
86400 - столько секунд в сутках

PawnoNoob
20.12.2017, 20:16
(1514764800 - 1483228800) / 86400 = 365
1514764800 - 01.01.2018
1483228800 - 01.01.2017
86400 - столько секунд в сутках

Я сюда не писал бы просто так. Я этот момент перепробовал. А если будет, например, 1514764801? При делении выходит не целое число.

BodyanZe
20.12.2017, 20:32
Имеем две даты:

static year, month, day; // конечная дата
static year2, month2, day2; // начальная дата
static year3, month3, day3; // итоговая разница
if(day < day2) // проверяем, больше ли дней в конечной дате, чем у начальной, если нет, то берём n-количество дней с 1 месяца
{
month--;
day += GetDaysInMonth(year, month);
}
if(month < month2) // та же проверка, что и с днями, только для месяцев
{
year--;
month+=12;
}
day3 = day - day2; // ищем разницу в днях
month3 = month - month2; // ищем разницу в месяцах
year3 = year - year2; // ищем разницу в годах
printf("Разница в %d дня(-ей), %d месяц(-а) и %d лет/год", day3, month3, year3); // выводим результат
return 1;
}
stock GetDaysInMonth(year, month) // узнаем кол-во дней у каждого месяца
{
switch(month)
{
case 1,3,5,7,8,10,12: return 31;
case 2:
{
if(IsLeapYear(year)) // проверка на високосный год
return 29;
else
return 28;
}
default: return 30;
}
return 1;
}

stock IsLeapYear(year)
{
return ( (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) );
}

Пример использования, найдём разницу между текущей датой и Новым Годом:

#include <a_samp>
main() {}

public OnGameModeInit()
{
static year = 2018, month = 1, day = 1;
static year2, month2, day2;
static year3, month3, day3;
getdate(year2, month2, day2);
if(day < day2)
{
month--;
day += GetDaysInMonth(year, month);
}
if(month < month2)
{
year--;
month+=12;
}
day3 = day - day2;
month3 = month - month2;
year3 = year - year2;
printf("Разница в %d дня(-ей), %d месяц(-а) и %d лет/год", day3, month3, year3);
return 1;
}
stock GetDaysInMonth(year, month)
{
switch(month)
{
case 1,3,5,7,8,10,12: return 31;
case 2:
{
if(IsLeapYear(year))
return 29;
else
return 28;
}
default: return 30;
}
return 1;
}

stock IsLeapYear(year)
{
return ( (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) );
}

В конечном итоге получаем 11 дней, 0 месяцев и 0 лет.
По такому же принципу можно искать разницу между каким-либо промежутком времени. (Скрипт вроде рабочий, перечекал на 10 дат :D)

- - - Добавлено - - -


Я сюда не писал бы просто так. Я этот момент перепробовал. А если будет, например, 1514764801? При делении выходит не целое число.

Если использовать unix-систему, то MARVEL написал верный пример, если будет число 1514764801, то выведет по прежнему 365 дней, ибо +1 это всего-лишь +1 секунда к общему времени.

DeimoS
20.12.2017, 21:12
Проще взять time_t из Open-GTO (https://github.com/Open-GTO/time_t/blob/08a9abaee502c61a68b0107658333be03252ac7f/time_t.inc) (или любую другую проверенную библиотеку по работе с временем) и не парить мозг велосипедами.
А даты приучиться хранить изначально в UNIX времени. Тогда и с часовыми поясами проблем не будет, и работать с датой будет проще простого.
Собственно, вот так будет выглядеть вcё:

new year,
month,
day,
hour,
minute,
second;
gmtime(большая_дата-меньшая_дата, year, month, day, hour, minute, second);
printf("%dг. %dмес. %dд. %dч. %dмин. %dсек.", year, month, day, hour, minute, second);
Если же даты изначально в БД хранятся, то в SQL есть свой функционал по работе с датами и лучше им пользоваться сразу

BodyanZe
20.12.2017, 21:28
Как вариант Сток..


stock UnixToDate(unix, &year, &month, &week, &day, &hour, &minute, &second)
{
year = unix / 31536000;
unix -= year*31536000;
month = unix / 2628000;
unix -= month*2628000;
week = unix / 604800;
unix -= week*604800;
day = unix / 86400;
unix -= day*86400;
hour = unix / 3600;
unix -= hour*3600;
minute = unix / 60;
unix -= minute*60;
second = unix;
return 1;
}

PawnoNoob
20.12.2017, 21:44
Проще взять time_t из Open-GTO (https://github.com/Open-GTO/time_t/blob/08a9abaee502c61a68b0107658333be03252ac7f/time_t.inc) (или любую другую проверенную библиотеку по работе с временем) и не парить мозг велосипедами.
А даты приучиться хранить изначально в UNIX времени. Тогда и с часовыми поясами проблем не будет, и работать с датой будет проще простого.
Собственно, вот так будет выглядеть вcё:

new year,
month,
day,
hour,
minute,
second;
gmtime(большая_дата-меньшая_дата, year, month, day, hour, minute, second);
printf("%dг. %dмес. %dд. %dч. %dмин. %dсек.", year, month, day, hour, minute, second);
Если же даты изначально в БД хранятся, то в SQL есть свой функционал по работе с датами и лучше им пользоваться сразу

А через mxdate можно такое реализовать? В базе дата и время хранятся в unix.

DeimoS
20.12.2017, 21:55
А через mxdate можно такое реализовать? В базе дата и время хранятся в unix.

Ну если там есть функции перевода UNIX времени в дату - да.
Если обе даты хранятся в БД и ты хочешь получить разницу между ними прямо при выгрузке, то никакие махинации на стороне сервера не нужны. Всё делается прямо в запросе и в качестве результата возвращается дата нужного формата

PawnoNoob
20.12.2017, 22:58
Ну если там есть функции перевода UNIX времени в дату - да.
Если обе даты хранятся в БД и ты хочешь получить разницу между ними прямо при выгрузке, то никакие махинации на стороне сервера не нужны. Всё делается прямо в запросе и в качестве результата возвращается дата нужного формата

И как это реализовать? Ну, в виде запроса.

DeimoS
21.12.2017, 01:17
И как это реализовать? Ну, в виде запроса.

Нужно всю ту же самую формулу реализовать в запросе самом. То бишь

UNIX_TIMESTAMP(новая_дата)-UNIX_TIMESTAMP(старая_дата)
получится разница в секундах. А далее всё то же самое.


UPD: Ааа, если тебе именно количество дней нужно получить, а не информацию в формате "год:месяц:день час:минута:секунда", то всё ещё проще.

SELECT TIMESTAMPDIFF(DAY, старая_дата, новая_дата) AS result WHERE ...
Количество дней вернётся как "result"

PawnoNoob
24.12.2017, 01:11
Нужно всю ту же самую формулу реализовать в запросе самом. То бишь

UNIX_TIMESTAMP(новая_дата)-UNIX_TIMESTAMP(старая_дата)
получится разница в секундах. А далее всё то же самое.


UPD: Ааа, если тебе именно количество дней нужно получить, а не информацию в формате "год:месяц:день час:минута:секунда", то всё ещё проще.

SELECT TIMESTAMPDIFF(DAY, старая_дата, новая_дата) AS result WHERE ...
Количество дней вернётся как "result"

Если честно, то не совсем понятно. Мне ведь нужно переводить unix-время в обычное, а после этого уже высчитывать количество дней? И что должно идти после "WHERE"?:acute:

Sp1ke
24.12.2017, 01:19
Если честно, то не совсем понятно. Мне ведь нужно переводить unix-время в обычное, а после этого уже высчитывать количество дней? И что должно идти после "WHERE"?:acute:

Пример запроса, если я правильно тебя понял:

SELECT TIMESTAMPDIFF(DAY, FROM_UNIXTIME(UNIX_TIMESTAMP()), FROM_UNIXTIME(UNIX_TIMESTAMP() + 86400 * 30)) AS result
Вместо функции UNIX_TIMESTAMP() необходимо подставить свое unix-время, кол-во дней - result

DeimoS
24.12.2017, 01:23
Если честно, то не совсем понятно. Мне ведь нужно переводить unix-время в обычное, а после этого уже высчитывать количество дней? И что должно идти после "WHERE"?:acute:

Так тебе в каком формате нужно выводить разницу во времени? Просто количество дней или количество секунд, минут, часов, дней, месяцев и лет?

PawnoNoob
24.12.2017, 21:25
Так тебе в каком формате нужно выводить разницу во времени? Просто количество дней или количество секунд, минут, часов, дней, месяцев и лет?

Мне нужно вывести просто количество дней.
В базе данных хранится всё в unix. Например: первая дата - 01.01.2017 (00:00) выглядит так: 1483228800; вторая дата - 01.01.2018 (00:00), соответственно, так: 1514764800. Мне необходимо узнать только количество дней и вывести их в соответствующей функции.
На выходе (после всех манипуляций, если можно так выразиться) должно быть примерно так: "Количество дней: 365".

DeimoS
24.12.2017, 21:52
SELECT TIMESTAMPDIFF(DAY, старая_дата, новая_дата) AS result FROM таблица WHERE ...
Количество дней вернётся как "result"

И всё. "старая_дата" и "новая_дата" замени нужными столбцами + условие допиши

PawnoNoob
24.12.2017, 22:04
И всё. "старая_дата" и "новая_дата" замени нужными столбцами + условие допиши

А какое должно быть условие?

DeimoS
24.12.2017, 22:19
Эмм, ну а даты чего ты сравниваешь? Если из аккаунта берёшь - ID аккаунта. В общем, всё, что позволит найти нужную строку в БД

PawnoNoob
24.12.2017, 22:25
Эмм, ну а даты чего ты сравниваешь? Если из аккаунта берёшь - ID аккаунта. В общем, всё, что позволит найти нужную строку в БД

Ах, точно. Всё, вопросов больше нет. Спасибо :clapping: