- Регистрация
- 27.12.2016
- Сообщения
- 289
- Благодарностей
- 404
- Баллы
- 63
ВСЕМ ДОБРА!
У любого труженика Zennoposter, а особенно у тех, кто работает с соцсетями, рано или поздно возникали задачи связанные с получением, сравнением или преобразованием даты и времени. В этой статье я рассмотрю работу с датой и временем с использованием методов языка C#. (Ни фига себе лонгрид получился )
В коробочном функционале Zenno имеется некоторый набор инструментов, однако он достаточно ограничен и позволяет получить лишь текущие значения даты и времени. Для работы с датой и временем я не пользуюсь стандартным функционалом ZP и не планировал о нем говорить, но в целях самообразования решил заглянуть в доступные методы ZP. Но начнем мы с пары теоретических замечаний:
Первое. UTC (Coordinated Universal Time) — всемирное координированное время это универсальное время, имеющее нулевой часовой пояс. Конечно, определение в Википедии отличается от сказанного мной, но для нас важно только то, что UTC выступает как точка отсчета для часовых поясов, а так же то, что все сервера в Интернете, независимо от местоположения, оперируют именно временем UTC.
Второе — это некоторые способы записи даты-времени, которые используются в разных культурах. Наиболее часто используемый формат — это сокращенное числовое отображение (для России 22.12.2020), где на первом месте идет число месяца, затем, после разделителя порядковый номер месяца, и далее (опять же после разделителя) год. Та же дата, записанная в американской традиции — 12/22/2020 — мы видим, что на первом месте идет месяц, а не число. Та же дата в международном формате выглядит так — 2020-12-23. Способы записи даты-времени, а так же разделители отличаются у разных народов, и это вносит изрядную сложность в понимание и обработку дат.
Предлагаю подробнее остановиться на описании некоторых строковых (т.е. типа string) форматов даты и времени, используемых в C# — это позволит лучше ориентироваться в форматах отображения даты и времени. С полным их описанием можно ознакомиться на странице Microsoft, которую рекомендую добавить в закладки. Итак, поехали:
"d" - день месяца, в диапазоне от 1 до 31. Числа месяца 1-9 при указании этого формата отображаются без нулей (пример формата d.M.yyyy и реальные даты - 1.1.2020, 12.10.2020 - ниже буду просто писать формат и соответствующее ему отображение);
"dd" — день месяца, в диапазоне от 01 до 31 (dd.MM.yyyy - 01.01.2020, 12.10.2020);
"M" — месяц, в диапазоне от 1 до 12 (d.M.yyyy - 1.1.2020, 12.10.2020; dd.M.yyyy - 01.1.2020);
"MM " — месяц, в диапазоне от 01 до 12 (d.MM.yyyy - 1.01.2020; dd.MM.yyyy - 01.01.2020);
"yyyy" — год в виде четырехзначного числа (dd.MM.yyyy - 01.01.0001, 01.01.2020);
"h" — часы в 12-часовом формате от 1 до 12 (h — 1, 10; MM/dd/yyyy h:mm tt - 01/01/2020 1:12 PM (1 января 2020 13:12), 01/24/2020 12:54 AM (24 января 2020 00:54));
"hh" — час в 12-часовом формате от 01 до 12 (hh — 01, 10; MM/dd/yyyy hh:mm tt - 01/01/2020 01:12 PM (1 января 2020 13:12), 01/24/2020 12:54 AM (24 января 2020 00:54));
"H" час в 24-часовом формате от 0 до 23 (H - 1, 23; dd.MM.yyyy H:m - 01.01.2020 1:1, 01.01.2020 14:50);
"HH" Час в 24-часовом формате от 00 до 23 (HH - 1, 23; dd.MM.yyyy HH:mm - 01.01.2020 01:01, 01.01.2020 14:50);
"m" — минуты, в диапазоне от 0 до 59 (m - 1, 12; MM/dd/yyyy h:m tt - 01/01/2020 1:1 PM (1 января 2020 13:01), 01/24/2020 12:54 AM (24 января 2020 00:54));
"mm" — минуты, в диапазоне от 00 до 59 (mm - 01, 12; MM/dd/yyyy hh:mm tt - 01/01/2020 01:01 PM (1 января 2020 13:01), 01/24/2020 12:54 AM (24 января 2020 00:54));
"s" секунды в диапазоне от 0 до 59; (dd.MM.yyyy HH:mm:s - 01.01.2020 13:52:1);
"ss" секунды в диапазоне от 00 до 59; (dd.MM.yyyy HH:mm:ss - 01.01.2020 13:52:01);
"tt" — указатель AM/PM (до полудня/после полудня) (MM/dd/yyyy hh:mm tt - 01/01/2020 01:01 PM (1 января 2020 13:01), 01/24/2020 12:54 AM (24 января 2020 00:54));
"zz" — часовой сдвиг от времени в формате UTC (универсального времени) с нулями в начале для значений из одной цифры (dd.MM.yyyy HH:mm zz - 01.01.2020 13:52 -07)
Разделители даты и времени так же можно указать явно — в России для разделения дат используется ".", в Англии-Америке "/" в универсальном представлении "-". То же и с временем — ru-RU ":", it-IT "." и т.д.
А теперь, вернемся к методам Zennoposter.
Для получения значения текущего времени в ZP используется макрос
{-TimeNow.Date-}
— в результате его выполнения у меня возвращается значение 05/18/2020 14:13:38. Я не знаю почему вывод даты происходит не в локальном формате Cultureinfo (установленном в русский стандарт), а в американской традиции — может потому, что основной язык моей системы английский?Однако, можно получить дату и в нужном формате, явно задав строку вывода —
{-TimeNow.Date dd.MM.yyyy HH:mm:ss-}
(результат — 05.05.2020 15:46:24),или
{-TimeNow.Date HH:mm:ss-}
(15:46:24),или так
{-TimeNow.Date MM/dd/yyyy HH-mm-ss-}
( 05/05/2020 15-47-42),или даже так
{-TimeNow.Date dddd dd MMMM yyyy-}
(Tuesday 05 May 2020).Подводя итог — можно задать любой разумный (а может и не очень) формат вывода даты в строку. Дата выводимая макросом представляется в локальном времени ПК, на котором выполняется.
Еще один доступный макрос ZP —
{-TimeNow.TimeNow-}
у меня он возвращает значение вида 2020-05-05 16-11-48--720. Дата указана в международном формате, соответствующем ISO 8601, а вот разделители во времени я привык видеть в виде ":", хотя это конечно не принципиально. Так же, меня смущает присутствие миллисекунд (мне не попадались задачи в которых они нужны). В этом макросе вывод в свой формат строки недоступен. Придумать применение для него в своих шаблонах я не смог.Следующий стандартный макрос, о котором стоит сказать —
{-TimeNow.UnixTime-}
. Возвращает значение вида 1588674065.50537, где до точки указано количество целых секунд прошедших с наступления эпохи Unix(подробнее о ней ниже). UnixTime выводится по времени UTC. Для чего нужны милли или микросекунды (а может пико или нано, не вникал), следующие после запятой, мне не ясно — имхо это лишний кубик по их удалению, но может имеется и возможность задать формат вывода.Остальные макросы Zenno позволяют получать месяц, день недели, день месяца, часы, минуты, секунды и миллисекунды текущей даты. Так как те же данные можно вывести подставляя свой формат в макрос
{-TimeNow.Date-}
, говорить о них отдельно не вижу смысла.Работа с датой и временем с использованием методов C#
Небольшое количество встроенных методов ZP могло бы оказаться большой проблемой, если бы не великий и могучий C#, доступный из кубика C#-кода. Академиев по программированию мы не заканчивали , с C# не на ты, поэтому прочитанная по теме инфа забывается, а на перечитывание микрософтовских доков и поиск готовых решений на форуме (здесь на самом деле немало инфы на тему) уходит приличное количество времени. Поэтому при очередной задаче, для экономии времени я решил создать для себя небольшой конспект, содержащий основные сведения по теме, который и лег в основу данной статьи. Естественно, при написании статьи использовались и материалы с форума — большое спасибо всем, кто помогает, отвечая на вопросы!
Примечание: Локальный часовой пояс моей машины равен +07 UTC (или +04 по Москве) — это так, чтобы в дальнейшем было понятно откуда берутся те или иные цифры в примерах. Весь приведенный код проверялся на работоспособность в PM 7.1. На момент публикации приведенные пути xpath для поиска элементов могут оказаться нерабочими в связи с изменением верстки на сайтах.
Для операций с датой и временем в C# имеются три (на самом деле конечно больше, но это слишком тонкие токости) основных объекта — DateTime (представляет конкретную дату и время), TimeSpan (представляет временной интервал), b DateTimeOffset (указывает конкретную дату и время, а так же смещение относительно времени в формате UTC (часовой пояс)).
Первое, что однозначно понадобится нам в работе, это получение текущей даты и времени. Для этого в структуре DateTime имеются специальные свойства. Если это нужно для дальнейшей работы с форматом DateTime — сравнения дат, преобразований и т.п., то получать время стоит в виде объекта DateTime:
C#:
//свойство возвращает дату и время по часовому поясу, установленному на локальном компьютере в формате, выбранном в регинальных и языковых настройках т.е. для ru-RU — dd.MM.yyyy HH:mm:ss (01.01.2020 01:56:00)
DateTime dt = DateTime.Now;
//А таким способом мы получим универсальное время UTC в региональном формате локали
DateTime dt = DateTime.UtcNow;
//это свойство вернет только текущие число, месяц и год, с нулями вместо времени — 29.02.2020 00:00:00
DateTime dt = DateTime.Today;
C#:
//возвращает дату и время по часовому поясу, установленному на локальном компьютере и в формате, выбранном в регинальных и языковых настройках, например для ru-RU 01.01.2020 01:56
string dt = DateTime.Now.ToString();
//А таким способом мы получим время UTC
string dt = DateTime.UtcNow.ToString();
C#:
DateTime dt = new DateTime(2010,02,12);// 12.02.2010 00:00:00
DateTime dt = new DateTime(2010,02,12,22,15,41); //12.02.2010 22:15:41
C#:
//Любая из этих строк преобразуется в объект DateTime 21.05.2020 00:22:10
string input0 = "21.05.2020 00:22:10";
string input1 = "21-05-2020 00:22:10";
string input2 = "21/05/2020 00:22:10";//а вот если строка будет вида "05/21/2020 00:22:10", т.е. сначала месяц, а после число (как приято в en-US) — получим ошибку распознавания
string input3 = "21/05.2020 00:22:10";
string input4 = "21 мая 2020 00:22:10";
DateTime dt = DateTime.Parse(input[0-4]); //все строки от input0 до input4 преобразуются в одинаковый формат 21.05.2020 00:22:10
//Если не указан год и время — год принимает значение текущего года, время устанавливается по нулям
string input5 = "21/05"; //так же можно указать 21.05 или 21-05 т.е. 21/05 = 21.05 = 21-05
DateTime dt = DateTime.Parse(input5); //результат 21.05.2020 00:00:00
C#:
string input6 = "06/23/2020"; //23.06.2020 по en-US
System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US");//задаем языковые (региональные) стандарты
DateTime dt = DateTime.ParseExact(input6, "d", culture);//Выполнение кода C# Результат: 23.06.2020 0:00:00
string input6 = "06/05/2020 12:25 AM";
System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US");
DateTime dt = DateTime.ParseExact(input6, "g", culture);//Выполнение кода C# Результат: 23.06.2020 0:25:00
C#:
string input7 = "2020 Вторник июня 23 14:35";
System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CreateSpecificCulture("ru-RU");
DateTime dt = DateTime.ParseExact(input7, "yyyy dddd MMMM dd HH:mm", culture);//Выполнение кода C# Результат: 23.06.2020 14:35:00
Но есть в Psrse одна особенность, о которой стоит помнить — если в строке явно указан часовой пояс (например 21.05.2020 00:22:10 +03), и мы попытаемся спарисить его на локальной системе:
C#:
string input ="21.05.2020 00:22:10 +03";
DateTime dt = DateTime.Parse(input);
На скрине выше еще несколько примеров парсинга с разными значениями timezone. Если же нужно получить только время, без учета часового пояса, стоит воспользоваться DateTimeOffset, в которой смещение сохраняется отдельно, и из которой можно получить объект DateTime без него:
C#:
string input ="21.05.2020 00:22:10 +03:00";
DateTimeOffset dto = DateTimeOffset.Parse(input);//Выполнение кода C# Результат: 21.05.2020 0:22:10 +03:00
//А теперь без труда получаем DateTime
DateTime dt = dto.DateTime;//Выполнение кода C# Результат: 21.05.2020 0:22:10
C#:
string input ="21.05.2020 00:22:10 +03:00";
DateTimeOffset dto = DateTimeOffset.Parse(input);//Выполнение кода C# Результат: 21.05.2020 0:22:10 +03:00
//А теперь без труда получаем DateTime UTC
DateTime dt = dto.DateTime;//Выполнение кода C# 20.05.2020 21:22:10
1. Для регистраций я (да и вы наверное тоже), пользуюсь автоматически сгенерированными профилями ZP, используя их данные. Эти профили, в своей структуре содержат такие св-ва как BornDay(день рождения), BornMonth(месяц рождения), BornYear (год рождения), представленные в числовом формате (int). На странице регистрации мыла всеми любимого ресурса Майлру, есть поле «месяц рождения», где месяцы указаны не в числовом значении, а по названиям (на данный момент майл изменил верстку, так что этот пример из прошлого, но для посмотреть сойдет).
Для клика по нужному месяцу, элемент можно искать по xpath по числовому значению месяца:
C#:
//Ищем нужный месяц, подставляя свойство профиля BornMonth
var he = instance.ActiveTab.FindElementByXPath(@"//div[@class='b-date__month']//div[contains(@class,'b-dropdown__list')]/a[@data-value="+project.Profile.BornMonth.ToString()+"]", 0);
C#:
//получаем название месяца с учетом языковых настроек локальной системы
string month = new DateTime(project.Profile.BornYear,project.Profile.BornMonth,project.Profile.BornDay).ToString("MMMM");
//Ищем нужный месяц
var he = instance.ActiveTab.FindElementByXPath(@"//div[@class='b-date__month']//div[contains(@class,'b-dropdown__list')]/a[@data-text="+month+"]", 0);
C#:
//здесь через класс System.Globalization.CultureInfo с помощью метода CreateSpecificCulture мы указываем в каких языковых стандартах нам надо вернуть наименование месяца ("en-EN"), а затем методом GetMonthName, принадлежащего
//классу DateTimeFormat, получаем наименование месяца. Сложно? Я б$#ть, сам в шоке, но не удивлюсь если есть методы попроще, которых я не нашел
string month = System.Globalization.CultureInfo.CreateSpecificCulture("en-EN").DateTimeFormat.GetMonthName(new DateTime(project.Profile.BornYear,project.Profile.BornMonth,project.Profile.BornDay).Month);
//Ищем нужный месяц
var he = instance.ActiveTab.FindElementByXPath(@"//div[@class='b-date__month']//div[contains(@class,'b-dropdown__list')]/a[@data-text="+month+"]", 0);
Теоретически, это можно сделать с помощью регулярок, но зачем, если есть DateTime? Допустим, что дни родждения хранятся в списке (скорее это будет таблица, но не будем усложнять), сегодняшних именинников сохраняем тоже в список. Поехали:
C#:
//массив дат для примера
string[] input = {"25.12",
"01.01.1985",
"19.07",
DateTime.Now.ToString("dd.MM"),
"05.07.1900"};
//создаем временный список и добавляем в него наш массив
List<string> bday = new List<string>(input);
//список куда будем сохранять сегодняшних именинников
List<string> bdayToday = new List<string>();
//текущая дата в строку, для сравнения с элементами списка
string dtnow = DateTime.Now.ToString("dd.MM");
foreach(string item in bday)
{
//парсим строку из списка
DateTime dtbday = DateTime.Parse(item);//результат будет вида 21.05.1981 00:00:00
//опять преобразуем объект DateTime в строку, чтобы избавиться лишних элементов — года, часов, минут, секунд
//т.е. оставляем только день и месяц
string bd = dtbday.ToString("dd.MM");//получим строку вида 21.05
//сравниваем элемент списка и строку с текущей датой
if(dtnow == bd)
{
//если строки совпадают, т.е. день и месяц рождения соотв. сегодняшнему дню-месяцу,
//сохраняем совпавшую строку в список сегодняшних именинников
bdayToday.Add(bd);
return bd;
}
else
{
project.SendInfoToLog(bd+" не совпадает с сегодняшней датой "+dtnow);
}
}
Продолжаем знакомиться с методами C#
Следующий необходимый пласт знаний — операции с объектами DateTime. Даты можно сравнивать, складывать, вычитать, добавлять к указанной дате годы, месяцы, дни,часы и т.п. И всему этому можно найти практическое применение. При сравнении стоит обратить внимание вот на что — часовой пояс сравниваемых дат должен быть одинаков, иначе можно получить неожиданный результат и баги в дальнейших действиях. Наиболее логично выяснить часовой пояс, возвращаемый сервером до построения логики обработки полученного времени и ориентироваться на него.
В структуре DateTime имеется свойство DateTimeKind, позволяющее указать какой часовой пояс использовался для даты — UTC, Local, или Unspecifed. Небольшая демонстрация:
C#:
//создаем объект DateTime 01.01.1970 00:00:00 указывая, что это локальное время
DateTime dt = new DateTime(1970,1,1,0,0,0,DateTimeKind.Local); // 01.01.1970 00:00:00 по локальному времени
//Преобразуем его в универсальное время
DateTime dtu = dt.ToUniversalTime();
C#:
//создаем объект DateTime 01.01.1970 00:00:00 указывая, что это время UTC
DateTime dt = new DateTime(1970,1,1,0,0,0,DateTimeKind.Utc);
//Преобразуем его в универсальное время
DateTime dtu = dt.ToUniversalTime();//Выполнение кода C# Результат: dt = 01.01.1970 0:00:00, dtu = 01.01.1970 0:00:00
C#:
//создаем объект DateTime 01.01.1970 00:00:00
DateTime dt = new DateTime(1970,1,1,0,0,0,DateTimeKind.Unspecified);
//Преобразуем его в универсальное время
DateTime dtu = dt.ToUniversalTime(); //Выполнение кода C# Результат: dt = 01.01.1970 0:00:00, dtu = 31.12.1969 17:00:00
//создаем объект DateTime 01.01.1970 00:00:00
DateTime dt = new DateTime(1970,1,1,0,0,0,DateTimeKind.Unspecified);
//Преобразуем его в локальное время
DateTime dtu = dt.ToLocalTime();//Выполнение кода C# Результат: dt = 01.01.1970 0:00:00, dtu = 01.01.1970 7:00:00
C#:
DateTime dt1 = new DateTime(2010,10,25,20,40,00);//25.10.2010 20:40:00
DateTime dt2 = new DateTime(2020,02,25,10,15,40);//25.02.2020 10:15:40
DateTime dt3 = new DateTime(2010,10,25);//25.10.2010 00:00:00
DateTime dt4 = new DateTime(2010,10,25);//25.10.2010 00:00:00
//оба метода вернут 1
int res = dt1.CompareTo(dt3);
res = DateTime.Compare(dt1, dt3);
//возвратят -1
int res = dt3.CompareTo(dt2);
res = DateTime.Compare(dt3, dt2);
//возвратят 0
int res = dt3.CompareTo(dt4);
res = DateTime.Compare(dt3, dt4);
C#:
//получаем текущую дату и добавляем к ней 30 сек
DateTime dt1 = DateTime.Now.AddSeconds(30);
//В цикле ожидаем момента, когда наступит время dt1
//количество итераций и паузу выполнения потока можно подобрать под свои нужды
for(int i=0; i<10; i++)
{
//Указана пауза 5сек, естсественно можно заменить на свою
Thread.Sleep(5000);
//Проверку наступления момента осуществляем с помощью метода CompareTo
if(DateTime.Now.CompareTo(dt1)==-1)
{
project.SendInfoToLog("Время еще не пришло",false);
}
else
{
project.SendInfoToLog("Время dt1 наступило");
//прерываем цикл
break;
}
}
return dt1;
Еще один метод сравнения двух дат DateTime.Equals — возвращает значение bool. Обратите внимание на пример, где dt1 — текущее локальное время, а dt2 — текущее время UTC. Сравнение этих, вроде бы одинаковых дат возвращает false — еще одно напоминание о необходимости приведения дат к одной таймзоне:
C#:
//текущее время в формате UTC
DateTime dt1 = DateTime.UtcNow;
//локальное текущее время
DateTime dt2 = DateTime.Now;
bool eq = DateTime.Equals(dt1, dt2); //Выполнение кода C# Результат: False
C#:
DateTime dt1 = new DateTime(2010,10,25,20,40,00);//25.10.2010 20:40:00
DateTime dt2 = new DateTime(2020,02,25,10,15,40);//25.02.2020 10:15:40
TimeSpan diff = dt2-dt1;//Выполнение кода C# Результат: 3409.13:35:40
C#:
DateTime dt1 = new DateTime(2010,10,25,20,40,00);//25.10.2010 20:40:00
DateTime dt2 = new DateTime(2020,02,25,10,15,40);//25.02.2020 10:15:40
TimeSpan diff = dt2.Subtract(dt1); //Выполнение кода C# Результат: 3409.13:35:40
C#:
DateTime dt1 = new DateTime(2010,10,25,20,40,00);//25.10.2010 20:40:00
DateTime dt2 = new DateTime(2020,02,25,10,15,40);//25.02.2020 10:15:40
int diff = dt2.Subtract(dt1).Days;// вернет целое количество дней - 3409
int diff = dt2.Subtract(dt1).Hours;// вернет целое количество часов -13
int diff = dt2.Subtract(dt1).Minutes; //соответственно минуты - 35
int diff = dt2.Subtract(dt1).Seconds; //ну и секунд - 40
C#:
//создаем объект DateTime 01.01.2000
DateTime dt = new DateTime(2000,1,1);
//прибавим к нему 20 лет
DateTime dtAdd = dt.AddYears(20);//Выполнение кода C# Результат: 01.01.2020 0:00:00
//создаем объект DateTime 01.01.2000
DateTime dt1 = new DateTime(2000,1,1);
//прибавим к нему 12 мес
DateTime dt1Add = dt1.AddMonths(12);//Выполнение кода C# Результат: 01.01.2001 0:00:00
C#:
DateTime dtAdd = dt.Add(10,0,0,0,0,0); //здесь указан интервал 10 лет
C#:
DateTime dt = new DateTime(2000,1,1,20,20,59);//новая дата 01.01.2000 20:20:59
//обнуляем секунды
dt = dt.AddSeconds(-dt.Second); //Выполнение кода C# Результат: 01.01.2000 20:20:00
Ну а теперь поговорим об одном из самых необходимых для интернета понятий — timestamp, или, по-другому, Unixtime.
Unixtime — это количество секунд, прошедших до текущего момента с так называемой эпохи Unix (Unix epoch). Момент ее наступления определен как 01.01.1970 00:00:00 UTC. Записывается unixtime в виде числа формата long (Int64). Используется повсеместно. Сразу хочу обратить внимание — все даты unixtime выражены в универсальном времени UTC, и если об этом забыть и попытаться получить timestamp приведенным ниже способом, получатся косяки и непонятки:
C#:
//unix time UTC
long udts = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
//локальное время
DateTime dt = DateTime.Now;
//01.01.1970 00:00:00 по локальному времени
DateTime uepoch = new DateTime(1970,1,1);
//локальное значение unixtime
long dts = Convert.ToInt64((dt-uepoch).TotalSeconds);
C#:
//unix time UTC
long udts = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
//unix time local
long ldts = DateTimeOffset.Now.ToUnixTimeSeconds();
//Выполнение кода C# Результат: udts = 1582122062; ldts = 1582122062
C#:
//unix time UTC
long udts = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
C#:
// время, которое необходимо получить в UnixTime
DateTime time = new DateTime(2020,2,19,20,34,0,DateTimeKind.Utc);
// установка времени
DateTime dateTime = new DateTime(1970, 1, 1,0,0,0,DateTimeKind.Utc);
// время в UnixTime
long dts = (time - dateTime).TotalSeconds;
C#:
// время, которое необходимо получить в UnixTime
DateTime time = new DateTime(2020,2,19,20,34,0,DateTimeKind.Utc);
// установка времени
DateTime dateTime = new DateTime(1970, 1, 1,0,0,0,DateTimeKind.Utc);
// время в UnixTime
long dts = Convert.ToInt64((time - dateTime).TotalSeconds);
//РАБОТАЕТ ТОЛЬКО В .NET 4.6 и выше. unix time для даты 19.02.2020 20:34:00 UTC
long dt = new DateTimeOffset(2020,2,19,20,34,0,TimeSpan.Zero).ToUnixTimeSeconds();//Выполнение кода C# Результат: dt = 1582144440; 1 способ - dts = 1582144440
Получение даты из unixtime — не менее востребованная фигня. Например, когда-то в одном из своих первых шаблонов, в группе VK методами API я собирал комменты к фотографиям альбома, и если комментарий был старше некоторой даты — выполнял определенные действия. Дата публикации через API возвращается как раз в виде timestamp, и чтобы сравнить ее с нужной датой можно либо конвертировать ее в дату, либо свою дату перегнать в unixtime (я пользовался именно этим вариантом, и по неопытности как раз использовал для получения дату с локальным временем вместо UTC, и после долго выяснял, почему комент оставленный в нужном диапазоне в него не попадает). Опять же сниппет с github (https://github.com/ZennoHelpers):
C#:
//ИЗ UNIXTIME В DATETIME
// если время UnixTime хранится в переменной проекта
long unixTime = long.Parse(project.Variables["unixTime"].Value);//так мы получаем timestamp из переменной проекта
//а это timestamp, полученный в предыдущем примере, дата 19.02.2020 20:34:00 UTC
long udts = 1582144440;
DateTime dateTime = (new DateTime(1970, 1, 1, 0, 0, 0, 0)).AddSeconds(udts).ToLocalTime();
C#:
// переменная с UnixTime
long udts = 1582144440;
//Получаем дату по UTC
DateTimeOffset dto = DateTimeOffset.FromUnixTimeSeconds(udts);
//Преобразуем в локальное время
DateTime dt2 = dto.DateTime.ToLocalTime();
И еще пара слов о timestamp — так как тип данных этого формата обычное целое число, то делать с ним можно ровно то же самое что и с числом — суммировать, умножать делить и т.п. Например timestamp для 01.01.1970 00:00:00 будет равен 0. Получить момент времени 02.01.1970 00:00:00 можно простым сложением 0 + 86400= 86400., где 86400 — это количество секунд в сутках. Чтобы из unixtime даты 19.02.2020 20:34:00 UTC получить unixtime 18.02.2020 20:34:00 UTC:
C#:
//отнимаем от timestamp 19.02.2020 20:34:00 UTC сутки
long diff = 1582144440 - 86400;
//Преобразуем в дату по UTC
DateTimeOffset dto = DateTimeOffset.FromUnixTimeSeconds(diff);
DateTime dt = dto.DateTime; //Выполнение кода C# Результат: 18.02.2020 20:34:00
Однако все не так просто — timestamp сделанный на локали (синхронизируемой с ntp-серверами мелкософтов), имеет неопределенную разницу в несколько секунд с timestamp отправленного сообщения. В связи с этой неопределенностью решил обнулять секунды и в локальном и в выпаршенном timestamp, и проверять отправку без них, т.к. вариант отправки сразу нескольких сообщений одному и тому же пользователю ничтожно мал. С локальным unixtime все прошло гладко, а вот с vk-шным получилось не очень:
C#:
long uts = 1582392137; //некоторый timestamp спаршенный из ВК (по времени UTC)
//конвертим в DateTimeOffset
DateTimeOffset dt = DateTimeOffset.FromUnixTimeSeconds(udts);
//удаляем секунды и конвертим в DateTime
DateTime ddt = dt.AddSeconds(-dt.Second).DateTime; //Вот тут закралась неприятность. Предполагаю, что при такой конвертации, свойство DateTimeKind принимает значение Unspecifed, что влечет за собой появление ошибки при возврате к формату юникс
//Мы получаем timestamp с временем, равным DateTime ddt с учетом timezone локальной системы (т.е., если на моем пк время UTC +07, то при конвертации ddt в unixtime, из его значение вычтется 7 часов сдвига)
long udts1 = new DateTimeOffset(ddt).ToUnixTimeSeconds();
return udts1;
C#:
//конвертим в DateTimeOffset
DateTimeOffset dt = DateTimeOffset.FromUnixTimeSeconds(udts);
//получаем объект DateTime, с указанием, что это UTC время, и удаляем из него секунды
DateTime ddt = DateTime.SpecifyKind(dt.AddSeconds(-dt.Second).DateTime, DateTimeKind.Utc);
//ну и обратно в unixtime
long udts1 = new DateTimeOffset(ddt).ToUnixTimeSeconds();
return udts1;
P.S. В прилагаемом шаблоне, для вашего удобства представлен весь приведенный в статье код. Удачи в работе!
- Тема статьи
- Нестандартные хаки
- Номер конкурса статей
- Тринадцатый конкурс статей
Вложения
-
83,1 КБ Просмотры: 752
Для запуска проектов требуется программа ZennoPoster или ZennoDroid.
Это основное приложение, предназначенное для выполнения автоматизированных шаблонов действий (ботов).
Подробнее...
Для того чтобы запустить шаблон, откройте нужную программу. Нажмите кнопку «Добавить», и выберите файл проекта, который хотите запустить.
Подробнее о том, где и как выполняется проект.
Последнее редактирование: