Qt5 имеет классы QDate, QTime и QDateTime для работы с датой и временем:
QDate
— это класс для работы с датой в григорианском календаре. У него есть методы для определения, сравнения и манипулирования датами.
QTime
— это класс для работы со временем. Он имеет методы для сравнения, определения и манипулирования временем.
QDateTime
— это класс, который объединяет QDate и QTime в одно целое.
На этом уроке мы рассмотрим почти всё, что связано с датой и временем в Qt5.
Дата и время
Объекты даты и времени могут быть инициализированы двумя основными способами: инициализация в конструкторе или создание пустых объектов и их последующее заполнение данными.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#include <QTextStream> #include <QDate> #include <QTime> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли // Создаем объект даты и помещаем в него год, месяц и день QDate dt1(2015, 4, 12); out << "The date is " << dt1.toString() << endl; // конвертируем нашу дату в строку и выводим на экран QDate dt2; dt2.setDate(2015, 3, 3); out << "The date is " << dt2.toString() << endl; QTime tm1(17, 30, 12, 55); out << "The time is " << tm1.toString("hh:mm:ss.zzz") << endl; // Создаем пустой объект времени QTime tm2; tm2.setHMS(13, 52, 45, 155); // передаем часы, минуты, секунды и миллисекунды // Выводим время, включая миллисекунды (по умолчанию они не выводятся) out << "The time is " << tm2.toString("hh:mm:ss.zzz") << endl; return 0; } |
Результат выполнения программы:
В следующем примере мы выведем текущую дату и время на экран:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <QTextStream> #include <QTime> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли QDate cd = QDate::currentDate(); // возвращаем текущую дату QTime ct = QTime::currentTime(); // возвращаем текущее время // Выполняем конвертацию даты и времени в строки и выводим их out << "Current date is: " << cd.toString() << endl; out << "Current time is: " << ct.toString() << endl; return 0; } |
Результат выполнения программы:
Сравнение дат
Операторы сравнения могут использоваться для сравнения дат. Мы можем сравнивать их позиции в календаре:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <QTextStream> #include <QTime> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли // Создаем 2 объекта с датами QDate dt1(2015, 4, 5); QDate dt2(2014, 4, 5); // Сравниваем даты и определяем, какая из них расположена раньше в календаре if (dt1 < dt2) { out << dt1.toString() << " comes before " << dt2.toString() << endl; } else { out << dt1.toString() << " comes after " << dt2.toString() << endl; } return 0; } |
Результат выполнения программы:
Операторы сравнения также можно использовать и с объектами классов QTime и QDateTime.
Определение високосного года
Високосный год — это год с одним дополнительным днем (29 февраля). Причиной, по которой добавляется этот день в календарь, является различие между астрономическим и календарным годом. Календарный год состоит из 365 дней. Астрономический год — это время, за которое Земля делает оборот вокруг Солнца (365.25 дня). Данная разница в 6 часов приводит к тому, что за 4 года мы получаем еще 1 дополнительные сутки. А для того, чтобы наш календарь всегда оставался актуальным, мы раз в четыре года прибавляем к февралю один дополнительный день, поэтому в григорианском календаре в високосный год февраль содержит 29 дней вместо обычных 28, а сам год состоит из 366 дней вместо обычных 365.
Статический метод QDate::isLeapYear() помогает определить, является ли год високосным. В следующей программе у нас есть список лет (с 2010 по 2016 год), среди которых мы вычисляем високосные:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <QTextStream> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли // Инициализация списка лет QList<int> years({2010, 2011, 2012, 2013, 2014, 2015, 2016}); // Перебираем все элементы списка и вычисляем високосные года foreach (int year, years) { if (QDate::isLeapYear(year)) { out << year << " is a leap year" << endl; } else { out << year << " is not a leap year" << endl; } } return 0; } |
Результат выполнения программы:
Стоит обратить внимание на то, что при инициализации списка лет, мы используем возможности стандарта языка C++11:
1 |
QList<int> years({2010, 2011, 2012, 2013, 2014, 2015, 2016}); |
Скорее всего, вам потребуется дополнительно включить данную возможность в проекте. Для этого в проектный файл .pro добавьте следующее:
Предопределенные и пользовательские форматы дат
Qt5 имеет несколько встроенных форматов дат. Метод toString() класса QDate принимает формат даты в качестве параметра. По умолчанию Qt5 устанавливает формат даты как Qt::TextDate
.
В следующем примере мы рассмотрим 8 предопределенных форматов отображения текущей даты:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <QTextStream> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли QDate cd = QDate::currentDate(); out << "Today is " << cd.toString(Qt::TextDate) << endl; out << "Today is " << cd.toString(Qt::ISODate) << endl; // используем международный стандарт вывода даты out << "Today is " << cd.toString(Qt::SystemLocaleShortDate) << endl; out << "Today is " << cd.toString(Qt::SystemLocaleLongDate) << endl; out << "Today is " << cd.toString(Qt::DefaultLocaleShortDate) << endl; out << "Today is " << cd.toString(Qt::DefaultLocaleLongDate) << endl; out << "Today is " << cd.toString(Qt::SystemLocaleDate) << endl; out << "Today is " << cd.toString(Qt::LocaleDate) << endl; return 0; } |
Результат выполнения программы:
Дата может быть представлена и в других форматах. В Qt5 мы также можем создавать собственные форматы дат. Другая версия метода toString() принимает строку, в которой мы можем использовать различные спецификаторы. Например, спецификатор d
обозначает отображение дня как числа без ведущего нуля. Спецификатор dd
обозначает отображение дня как числа с ведущим нулем.
В следующей таблице перечислены доступные выражения, которые мы можем использовать для определения пользовательских форматов дат:
Выражение | Вывод |
d | День в виде числа без ведущего нуля (от 1 до 31) |
dd | День в виде числа с ведущим нулем (от 01 до 31) |
ddd | Сокращенное название дня недели (например, от «Пн» до «Вс»). Используется метод QDate::shortDayName(). |
dddd | Полное название дня недели (например, от «Понедельник» до «Воскресенье»). Используется метод QDate::longDayName(). |
M | Месяц в виде числа без ведущего нуля (от 1 до 12) |
MM | Месяц в виде числа с ведущим нулем (от 01 до 12) |
MMM | Сокращенное название месяца (например, от «Янв» до «Дек»). Используется метод QDate::shortMonthName(). |
MMMM | Полное название месяца (от «Январь» до «Декабрь»). Используется метод QDate::longMonthName(). |
yy | Год в виде двузначного числа (от 00 до 99) |
yyyy | Год в виде четырехзначного числа. Если год отрицательный, то дополнительно добавляется знак минуса. |
Рассмотрим 4 варианта пользовательских форматов времени:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <QTextStream> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли QDate cd = QDate::currentDate(); out << "Today is " << cd.toString("yyyy-MM-dd") << endl; // в качестве разделителя используем дефис out << "Today is " << cd.toString("yy/M/dd") << endl; // в качестве разделителя используем слэш out << "Today is " << cd.toString("d. M. yyyy") << endl; // в качестве разделителя используем точку out << "Today is " << cd.toString("d-MMMM-yyyy") << endl; // в качестве разделителя используем дефис return 0; } |
Результат выполнения программы:
Предопределенные и пользовательские форматы времени
Qt5 содержит несколько предопределенных форматов для отображения времени. Стандартные спецификаторы формата времени идентичны тем, которые используются в форматах даты. В Qt5 формат времени по умолчанию отображается с помощью Qt::TextDate
.
В качестве примера давайте рассмотрим 8 предопределенных форматов отображения текущего времени:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <QTextStream> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли QTime ct = QTime::currentTime(); out << "The time is " << ct.toString(Qt::TextDate) << endl; out << "The time is " << ct.toString(Qt::ISODate) << endl; out << "The time is " << ct.toString(Qt::SystemLocaleShortDate) << endl; out << "The time is " << ct.toString(Qt::SystemLocaleLongDate) << endl; out << "The time is " << ct.toString(Qt::DefaultLocaleShortDate) << endl; out << "The time is " << ct.toString(Qt::DefaultLocaleLongDate) << endl; out << "The time is " << ct.toString(Qt::SystemLocaleDate) << endl; out << "The time is " << ct.toString(Qt::LocaleDate) << endl; return 0; } |
Результат выполнения программы:
С помощью спецификаторов мы можем создавать пользовательские форматы времени. В таблице ниже приведен список спецификаторов, доступных для использования:
Выражение | Вывод |
h | Час без ведущего нуля (от 0 до 23 или от 1 до 12, если включен режим AM/PM ) |
hh | Час с ведущим нулем (от 00 до 23 или от 01 до 12, если включен режим AM/PM) |
H | Час без ведущего нуля (от 0 до 23, даже если включен режим AM/PM) |
HH | Час с ведущим нулем (от 00 до 23, даже если включен режим AM/PM) |
m | Минуты без ведущего нуля (от 0 до 59) |
mm | Минуты с ведущим нулем (от 00 до 59) |
s | Секунды без ведущего нуля (от 0 до 59) |
ss | Секунды с ведущим нулем (от 00 до 59) |
z | Миллисекунды без ведущего нуля (от 0 до 999) |
zzz | Миллисекунды с ведущим нулем (от 000 до 999) |
AP или A | Используется отображение AM/PM. AP будет заменен на «AM» или «PM» |
ap или a | Используется отображение am/pm. ap будет заменен на «am» или «pm» |
t | Временная зона (например, «CEST» = «Центральноевропейское летнее время») |
Создадим 4 пользовательских формата времени:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <QTextStream> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли QTime ct = QTime::currentTime(); out << "The time is " << ct.toString("hh:mm:ss.zzz") << endl; // добавили вывод миллисекунд out << "The time is " << QLocale("Russian").toString(ct,"h:m:s a") << endl; // добавили идентификаторы "am/pm" (до полудня/после полудня) out << "The time is " << QLocale("Russian").toString(ct,"H:m:s A") << endl; // добавили идентификаторы "AM/PM" (До полудня/После полудня) out << "The time is " << QLocale("Russian").toString(ct,"h:m AP") << endl; // добавили идентификаторы "AM/PM" (До полудня/После полудня) out << "The version of Qt5 is " << qVersion() << endl; return 0; } |
Результат выполнения программы:
Работа с днями недели
Метод dayOfWeek() возвращает число, которое представляет день недели, где 1
— это понедельник, а 7
— воскресенье. В следующей программе мы отобразим текущий день недели в формате короткого и полного названия:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <QTextStream> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли // Получаем текущую дату QDate cd = QDate::currentDate(); int wd = cd.dayOfWeek(); // определяем название дня недели QLocale loc; out << "Today is " << QDate::shortDayName(wd) << endl; // выводим короткое название дня недели out << "Today is " << QDate::longDayName(wd) << endl; // выводим полное название дня недели return 0; } |
Результат выполнения программы:
Мы можем вычислить количество дней в конкретном месяце с помощью метода daysInMonth(), а количество дней в году с помощью метода daysInYear(). В следующем примере мы создадим пять объектов даты и вычислим количество дней в этих месяцах и в конкретном году:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include <QTextStream> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли QList<QString> months; months.append("January"); months.append("February"); months.append("March"); months.append("April"); months.append("May"); months.append("June"); months.append("July"); months.append("August"); months.append("September"); months.append("October"); months.append("November"); months.append("December"); // Создаем объекты с датами QDate dt1(2015, 9, 18); QDate dt2(2015, 2, 11); QDate dt3(2015, 5, 1); QDate dt4(2015, 12, 11); QDate dt5(2015, 1, 21); // С помощью метода daysInMonth() получаем количество дней в месяцах, указанных в объектах с датами out << "There are " << dt1.daysInMonth() << " days in " << months.at(dt1.month()-1) << endl; out << "There are " << dt2.daysInMonth() << " days in " << months.at(dt2.month()-1) << endl; out << "There are " << dt3.daysInMonth() << " days in " << months.at(dt3.month()-1) << endl; out << "There are " << dt4.daysInMonth() << " days in " << months.at(dt4.month()-1) << endl; out << "There are " << dt5.daysInMonth() << " days in " << months.at(dt5.month()-1) << endl; // С помощью метода daysInYear() получаем количество дней в году, указанном в объекте с датой out << "There are " << dt1.daysInYear() << " days in year " << QString::number(dt1.year()) << endl; return 0; } |
Результат выполнения программы:
Проверка корректности даты
Для проверки корректности (валидности) даты используется метод isValid():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include <QTextStream> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли // Первые две даты корректны, а вот третья - нет (т.к. февраль может иметь 28 или 29 дней) QList<QDate> dates({QDate(2015, 5, 11), QDate(2015, 8, 1), QDate(2015, 2, 30)}); for (int i=0; i < dates.size(); i++) { // Выводим информацию о корректности проверяемой даты на экран if (dates.at(i).isValid()) { out << "Date " << i+1 << " is a valid date" << endl; } else { out << "Date " << i+1 << " is not a valid date" << endl; } } return 0; } |
Результат выполнения программы:
Мы можем легко посчитать, сколько дней осталось до какой-нибудь конкретной даты с помощью метода daysTo() или какая дата наступит по истечении определенного количества дней с помощью метода addDays(). Допустим, мы хотим узнать, какая дата будет через 55 дней после 11 мая 2019 года, а также сколько дней осталось до Рождества:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <QTextStream> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли QDate dt(2019, 5, 11); // указываем дату QDate nd = dt.addDays(55); // возвращаем дату через 55 дней после указанной выше даты QDate xmas(2019, 12, 24); out << "55 days from " << dt.toString() << " is " << nd.toString() << endl; out << "There are " << QDate::currentDate().daysTo(xmas) // возвращаем количество дней до наступления Рождества << " days till Christmas" << endl; return 0; } |
Результат выполнения программы:
Класс QDateTime
Объект класса QDateTime содержит календарную дату и время. Он является комбинацией классов QDate и QTime и имеет много схожих методов, а его использование идентично использованию этих двух классов. В следующем примере мы выведем на экран текущую дату и время:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <QTextStream> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли QDateTime cdt = QDateTime::currentDateTime(); out << "The current datetime is " << cdt.toString() << endl; // выводим полную дату со временем out << "The current date is " << cdt.date().toString() << endl; // выводим только дату out << "The current time is " << cdt.time().toString() << endl; // выводим только время return 0; } |
Результат выполнения программы:
Юлианская дата
Юлианская дата — это астрономический способ измерения времени, который начинает свой отсчет с начала Юлианского периода. Не следует её путать с Юлианским календарем. Юлианский период начался в 4713 году до нашей эры (детально об этом здесь). Помимо астрономии, Юлианские даты также часто используются военными и в вычислениях, проводимых на мейнфреймах.
В следующей программе мы вычислим Григорианскую и Юлианскую дату для текущего дня:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <QTextStream> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли QDate cd = QDate::currentDate(); out << "Gregorian date for today: " << cd.toString(Qt::ISODate) << endl; // выводим Григорианскую дату out << "Julian day for today: " << cd.toJulianDay() << endl; // выводим Юлианский день return 0; } |
Результат выполнения программы:
Следующий пример показывает, сколько дней прошло с момента двух исторических событий:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#include <QTextStream> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли // Ниже представлены 2 даты битв из Наполеоновской эпохи QDate bordate(1812, 9, 7); QDate slavdate(1805, 12, 2); QDate cd = QDate::currentDate(); // Теперь вычисляем, сколько Юлианских дней на текущий момент прошло от начала Юлианского периода до текущего момента и до дат битв за Славков и Бородино int j_today = cd.toJulianDay(); int j_borodino = bordate.toJulianDay(); int j_slavkov = slavdate.toJulianDay(); // Теперь посчитаем, сколько дней прошло от каждого из двух вышеприведенных событий до настоящего момента out << "Days since Slavkov battle: " << j_today - j_slavkov << endl; out << "Days since Borodino battle: " << j_today - j_borodino << endl; return 0; } |
Результат выполнения программы:
UTC-время
У нас есть 24 часовых пояса. В каждом часовом поясе существует свое местное время, которое может изменяться при переходе на летнее время.
Существует потребность в едином глобальном времени. Единое глобальное время поможет избежать путаницы с часовыми поясами и переходом на летнее время. В качестве основного стандарта времени был выбран стандарт UTC (Всемирное координированное время). UTC используется в авиации, в прогнозах погоды, в управлении воздушным движением и т.д. В отличие от местного времени, UTC не меняется со сменой сезонов.
В следующем примере мы вычислим текущую дату и время, а затем выведем её в форматах UTC и локального времени:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <QTextStream> #include <QDate> int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли QDateTime cdt = QDateTime::currentDateTime(); // Получаем время в формате UTC, конвертируем его в строку и выводим на экран out << "Universal datetime: " << cdt.toUTC().toString() << endl; // Получаем локальное время, конвертируем его в строку и выводим на экран out << "Local datetime: " << cdt.toLocalTime().toString() << endl; return 0; } |
Результат выполнения программы:
Unix-время
Эпоха — это момент времени, выбранный в качестве начала определенной эры. Например, в западных христианских странах эпоха времени начинается с нулевого дня, когда родился Иисус. Другой пример — французский республиканский календарь, который использовался в течение двенадцати лет. Эта эпоха была началом Республиканской эры, которая была провозглашена 22 сентября 1792 года, в день провозглашения Первой Республики и упразднения монархии.
У компьютеров также есть свои эпохи. Одной из самых популярных является эпоха Unix. Эпоха Unix — это время 00:00:00 в формате UTC 1 января 1970 года (или 1970-01-01T00:00:00Z ISO 8601). Дата и время в компьютере определяются в соответствии с количеством секунд, прошедших с определенной эпохи для этого компьютера или платформы.
Unix-время — это количество секунд, прошедших с эпохи Unix. В следующем примере мы будем использовать две функции Qt5, чтобы получить Unix-время и преобразовать его в читабельную версию и обратно:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <QTextStream> #include <QDate> #include <ctime> // подключаем необходимый заголовочный файл int main() { QTextStream out(stdout); out.setCodec("CP866"); // устанавливаем CP866-кодировку для консоли time_t t = time(0); // получаем Unix-время out << t << endl; QDateTime dt; dt.setTime_t(t); // конвертируем Unix-время в обычный формат даты out << dt.toString() << endl; QDateTime cd = QDateTime::currentDateTime(); out << cd.toTime_t() << endl; // метод toTime_t() также может быть использован для получения Unix-времени return 0; } |
Результат выполнения программы:
На этом всё! До следующего урока!
Интересная статья, но все примеры даны на чтение даты-времени. А если я хочу скорректировать и записать свою дату в Windows, как быть?
У меня нормально работает только если не менять кодировку.
Если ставить out.setCodec("CP866"), то выводит в консоль иероглифы
Ох, как я Вас прекрасно понимаю. Сам намучился с этими кодировками. В итоге плюнул и делаю как раньше:
Соответственно вот это становится ненужным
а весь вывод кидаю в std::cout
Есть вопрос ,в пользовательском формате времени при вводе без QLocale а только через QTime.toString добавление AP A a в конце не меняет формат отображения
обязательно ли использовать QLocale для этого?
Проверьте настройки локали вашей системы:
Windows 10 -> вбить в панели поиска "Панель управления" -> "Региональные стандарты" -> кнопка "Дополнительные параметры…" ->вкладка "Время" -> проверить настройки "Обозначение времени до полудня (AM)" и "Обозначение времени после полудня (PM)" -> если там пусто, то из выпадающих списков выбрать соответствующие параметры. Как всё сделаете, проверьте вашу программу без явного указания локали через QLocale…
Спасибо!
У меня просит писать именно Qt::endl. Как сделать так, чтобы можно было писать endl без пространства имён Qt
Странно…
Только что проверил на Windows 10 + Qt 5.14.2 — всё нормально. Попробуйте пересоздать проект.
P.S.: В каком конкретно примере появляется данная ошибка? Какая версия Qt и ОС? Если есть возможность — загрузите куда-нить скриншот с полным описание ошибки.
Qt::endl это начинается с версии Qt 5.15
Я сделал что то типо:
И в коде везде использую Qt::endl
И так же с другими манипуляторами (hex, flush)
Добавить перед первым использованием строку:
мне кажется есть ещё одна очень важная функция, которую не расмотрели: QClass::fromString(QSrring format), где QClass может быть как время, датой или общее
Не совсем понял, о какой функции идет речь? Можно ссылку на документацию?
QClass -> QDateTime. Видимо читали и писал комментарии уже сонным
https://doc.qt.io/QT-5/qdatetime.html#fromString
Классная статья )