Developing for Sailfish OS: Features date and time zones
Hello! This article is a continuation of cycle of articles, dedicated to developing applications for the mobile platform Sailfish OS. This time we will talk about the work with dates and time zones in QML. Let's start the article with a description of the problem, and then move on to ways to solve it.
When developing Sailfish OS apps quite often in one form or another will have to work with dates and time (as, indeed, when developing for any other platform). To specify a date and time to applications Sailfish OS use components such as DatePickerDialog TimePickerDialog. Inside to control the date and time they use the QML object Date inherited from the standard JavaScript object Datethat does not support the ability to create a date and time with time-zone other than UTC or local. Object Date simply has a constructor and methods for this.
the
It would seem that here should help the third designer from the list if you pass it a string with the date, time and offset from UTC, but no. The time zone object will still be local, and not the one specified in the offset.
the
You may ask: "And why do we use time zones? Why can't you call time in UTC?" And I'll tell You: Yes, sometimes time zones don't make sense. It is sufficient to use only the date and time. For example, if Your workday starts at 9:00, it is unlikely that you expect Your colleague from Kamchatka will start to work at 18:00. However, in the case of the regular events occurring in one moment of time in different time zones, the time zone still needed. For example, daily discussion of current work on the project starts at 10:00 for You and 19:00 for Your colleagues in Kamchatka.
One of the solutions to the problem on creation date and time setting time zone was using the same third-party libraries: timezone-js and moment.js. But they were wrong, because DatePickerDialog and TimePickerDialog don't know anything about these libraries, but on the inside are actively using the standard Date, is incompatible with objects created by using timezone-js and moment.js. In the end, we have developed two other solutions.
The first solution that came to mind is creating its own JavaScript object to manage the date and time. Such an object should allow to store the date, time and information about time zone, and most importantly — to change the date and time using the Sailfish OS components DatePickerDialog and TimePickerDialog, without affecting the time zone.
To create a custom JavaScript object, you need JavaScript in a separate file to define the constructor function.
the
The constructor function accepts a string of form "yyyy-MM-ddTHH:mm:ssZ", where Z is the offset from UTC of the form "[+-]HH:mm", ISO standard 8601. From the part of the string object is created Date and assigned to the property dateTime. This property will contain information about the date and time, excluding time zone. The rest of the line that contains the offset from UTC is stored in a separate property utcOffset. Now we can create an object that will contain information about the date, time, and time zone.
the
We will add to our object method that returns the date and time in the format "yyyy-MM-ddTHH:mm:ssZ".
the
Often in applications that work with date and time, required to display the appropriate values. We as developers must ensure that all users of the date and time will be displayed correctly according to the current locale. For this, we will add our JavaScript object methods that return strings with language-dependent representation of date and time.
the
Thus we have an object that stores and allows you to edit information about the date, time and time zone, is created using the string in a specific format, can return a string in the same format, and the formatted string in the current locale. Such a facility will allow us to operate with date and time in the required timezone.
Consider the example of using object CustomDateTime.
the
The example contains the components ValueButton to edit date and time. By clicking on one component offers a DatePickerDialog, by clicking on the second TimePickerDialog. Detailed component ValueButton for editing the time. Object CustomDateTime is created as a property of the component Page is used to display date and time in ValueButton with the property value, and to transmit the values in DatePickerDialog and TimePickerDialog, as described in the event handler, onClicked. There is described receiving data from DatePickerDialog and TimePickerDialog and updates properties dateTime object CustomDateTime.
You have created a JavaScript object CustomDateTime that can store information about the date, time and timezone, and also allows you to edit the date and time using the DatePickerDialog and TimePickerDialog.
The downside of this solution is that the JavaScript object doesn't support binding properties. In this example, after changing the date or time (change the properties on dateTime object CustomDateTime) does not update the property value object ValueButton, i.e. visually on the screen there will be no changes, despite the fact that the object CustomDateTime has changed. This is due to the fact that the property dateTime object CustomDateTime can be bound to a property value object ValueButton.
In cases where the binding properties does not matter, you can use the above solution, but in other cases it is necessary to refer to decision No. 2.
The second solution is create your own QML component, in particular component type QtObject. QtObject is the most "lightweight" standard QML type has no visual component and can be useful when creating object models. And most importantly — QML-components support binding properties. Rewrite JavaScript object defined above, a QML-component.
the
The code became more concise constructor function and methods of the JavaScript object replaced by properties in QtObject. Now, to create a new object we need to use the standard QML syntax and define only one property dateTimeStringToSet, all other properties will be automatically calculated, as will binding properties.
the
Let's rewrite the example that was higher with the use of QML object CustomDateTime.
the
It is easy to see that the changes is not much. The property Declaration is replaced with Declaration QML-component CustomDateTime and instead of functions toLocaleDateString() and toLocaleTimeString() uses properties localeDateString and localeTimeString. Throughout the rest of the code is not changed, but now the binding properties. Change the properties on dateTime object CustomDateTime will update all the object properties and properties of localeTimeString in particular that will update the appearance of the object ValueButton.
The result was a solution for managing the date, time and information about time zone support components for editing date and time in Sailfish OS. The solution is to create your own QML component and use it as a model. This object allows you to store the date, time and timezone, and also supports binding properties and can be used inside Sailfish OS components DatePickerDialog and TimePickerDailog for editing. The source code of the described example is available in GitHub.
Author: Ivan Shields
Article based on information from habrahabr.ru
Description
When developing Sailfish OS apps quite often in one form or another will have to work with dates and time (as, indeed, when developing for any other platform). To specify a date and time to applications Sailfish OS use components such as DatePickerDialog TimePickerDialog. Inside to control the date and time they use the QML object Date inherited from the standard JavaScript object Datethat does not support the ability to create a date and time with time-zone other than UTC or local. Object Date simply has a constructor and methods for this.
the
new Date();
new Date(value);
new Date(dateString);
new Date(year, month[, day[, hour[, minute[, second[, millisecond]]]]]);
It would seem that here should help the third designer from the list if you pass it a string with the date, time and offset from UTC, but no. The time zone object will still be local, and not the one specified in the offset.
the
new Date('Jan 30 2017 10:00:00 GMT+0700') // Jan 30 2017 06:00:00 GMT+0300
You may ask: "And why do we use time zones? Why can't you call time in UTC?" And I'll tell You: Yes, sometimes time zones don't make sense. It is sufficient to use only the date and time. For example, if Your workday starts at 9:00, it is unlikely that you expect Your colleague from Kamchatka will start to work at 18:00. However, in the case of the regular events occurring in one moment of time in different time zones, the time zone still needed. For example, daily discussion of current work on the project starts at 10:00 for You and 19:00 for Your colleagues in Kamchatka.
One of the solutions to the problem on creation date and time setting time zone was using the same third-party libraries: timezone-js and moment.js. But they were wrong, because DatePickerDialog and TimePickerDialog don't know anything about these libraries, but on the inside are actively using the standard Date, is incompatible with objects created by using timezone-js and moment.js. In the end, we have developed two other solutions.
Solution 1
The first solution that came to mind is creating its own JavaScript object to manage the date and time. Such an object should allow to store the date, time and information about time zone, and most importantly — to change the date and time using the Sailfish OS components DatePickerDialog and TimePickerDialog, without affecting the time zone.
To create a custom JavaScript object, you need JavaScript in a separate file to define the constructor function.
the
// CustomDateTime.js
function CustomDateTime(dateTimeString) {
this.dateTime = Date.fromLocaleString(Qt.locale(),
dateTimeString.substring(0, dateTimeString.length - 6),
"yyyy-MM-ddTHH:mm:ss");
this.utcOffset = dateTimeString.substring(dateTimeString.length - 6);
}
The constructor function accepts a string of form "yyyy-MM-ddTHH:mm:ssZ", where Z is the offset from UTC of the form "[+-]HH:mm", ISO standard 8601. From the part of the string object is created Date and assigned to the property dateTime. This property will contain information about the date and time, excluding time zone. The rest of the line that contains the offset from UTC is stored in a separate property utcOffset. Now we can create an object that will contain information about the date, time, and time zone.
the
var myDateTime = new CustomDateTime("2016-12-22T13:40:00+05:00");
print(myDateTime.utcOffset); // "+05:00"
myDateTime.dateTime = new Date(2016, 11, 23, 13, 00, 00);
print(myDateTime.dateTime); // 23 Dec 2016 13:00:00 GMT+03:00
print(myDateTime.utcOffset); // "+05:00"
We will add to our object method that returns the date and time in the format "yyyy-MM-ddTHH:mm:ssZ".
the
// CustomDateTime.js
CustomDateTime.prototype.toISO8601String = function() {
return this.dateTime.toLocaleString(Qt.locale(), "yyyy-MM-ddTHH:mm:ss").concat(this.utcOffset);
}
Often in applications that work with date and time, required to display the appropriate values. We as developers must ensure that all users of the date and time will be displayed correctly according to the current locale. For this, we will add our JavaScript object methods that return strings with language-dependent representation of date and time.
the
// CustomDateTime.js
CustomDateTime.prototype.toLocaleDateString = function() {
return Qt.formatDate(this.dateTime, Qt.SystemLocaleShortDate);
}
CustomDateTime.prototype.toLocaleTimeString = function() {
return Qt.formatTime(this.dateTime, "HH:mm");
}
CustomDateTime.prototype.toLocaleDateTimeString = function() {
return this.toLocaleDateString() + "" + this.toLocaleTimeString();
}
Thus we have an object that stores and allows you to edit information about the date, time and time zone, is created using the string in a specific format, can return a string in the same format, and the formatted string in the current locale. Such a facility will allow us to operate with date and time in the required timezone.
Consider the example of using object CustomDateTime.
the
//...
import "../model/CustomDateTime.js" as CustomDateTime
Page {
property var сustomDateTime: new CustomDateTime.CustomDateTime("2017-01-15T13:45:00+05:00")
SilicaFlickable {
anchors.fill: parent
contentHeight: column.height
Column {
id: column
//...
ValueButton {
label: qsTr("Date").concat(":")
value: сustomDateTime.toLocaleDateString()
//...
}
ValueButton {
width: parent.width
label: qsTr("Time").concat(":")
value: сustomDateTime.toLocaleTimeString()
onClicked: {
var dialog = pageStack.push("Sailfish.Silica.TimePickerDialog",
{ hour: сustomDateTime.dateTime.getHours(),
minute: сustomDateTime.dateTime.getMinutes()});
dialog.accepted.connect(function() {
сustomDateTime.dateTime = new Date(сustomDateTime.dateTime.getFullYear(),
сustomDateTime.dateTime.getMonth(),
сustomDateTime t.dateTime.getDate(),
dialog.hour dialog.minute);
});
}
}
}
}
}
The example contains the components ValueButton to edit date and time. By clicking on one component offers a DatePickerDialog, by clicking on the second TimePickerDialog. Detailed component ValueButton for editing the time. Object CustomDateTime is created as a property of the component Page is used to display date and time in ValueButton with the property value, and to transmit the values in DatePickerDialog and TimePickerDialog, as described in the event handler, onClicked. There is described receiving data from DatePickerDialog and TimePickerDialog and updates properties dateTime object CustomDateTime.
You have created a JavaScript object CustomDateTime that can store information about the date, time and timezone, and also allows you to edit the date and time using the DatePickerDialog and TimePickerDialog.
The downside of this solution is that the JavaScript object doesn't support binding properties. In this example, after changing the date or time (change the properties on dateTime object CustomDateTime) does not update the property value object ValueButton, i.e. visually on the screen there will be no changes, despite the fact that the object CustomDateTime has changed. This is due to the fact that the property dateTime object CustomDateTime can be bound to a property value object ValueButton.
In cases where the binding properties does not matter, you can use the above solution, but in other cases it is necessary to refer to decision No. 2.
Solution 2
The second solution is create your own QML component, in particular component type QtObject. QtObject is the most "lightweight" standard QML type has no visual component and can be useful when creating object models. And most importantly — QML-components support binding properties. Rewrite JavaScript object defined above, a QML-component.
the
// CustomDateTime.qml
import QtQuick 2.0
QtObject {
property string dateTimeStringToSet
property date dateTime: Date.fromLocaleString(Qt.locale(),
dateTimeStringToSet.substring(0, dateTimeStringToSet.length - 6),
"yyyy-MM-ddTHH:mm:ss")
property string utcOffset: dateTimeStringToSet.substring(dateTimeStringToSet.length - 6)
property string localeDateString: Qt.formatDate(dateTime, Qt.SystemLocaleShortDate)
property string localeTimeString: Qt.formatTime(dateTime, "HH:mm")
property string localeDateTimeString: localeDateString.concat(" ").concat(localeTimeString)
property string iso8601String: dateTime.toLocaleString(Qt.locale(), "yyyy-MM-ddTHH:mm:ss")
.concat(utcOffset)
}
The code became more concise constructor function and methods of the JavaScript object replaced by properties in QtObject. Now, to create a new object we need to use the standard QML syntax and define only one property dateTimeStringToSet, all other properties will be automatically calculated, as will binding properties.
the
CustomDateTime {
dateTimeStringToSet: "2017-01-15T13:45:00+05:00"
}
Let's rewrite the example that was higher with the use of QML object CustomDateTime.
the
//...
Page {
CustomDateTime {
id: customDateTime
dateTimeStringToSet: "2017-01-15T13:45:00+05:00"
}
SilicaFlickable {
anchors.fill: parent
contentHeight: column.height
Column {
id: column
//...
ValueButton {
label: qsTr("Date").concat(":")
value: customDateTime.localeDateString
//...
}
ValueButton {
width: parent.width
label: qsTr("Time").concat(":")
value: customDateTime.localeTimeString
onClicked: {
var dialog = pageStack.push("Sailfish.Silica.TimePickerDialog",
{ hour: customDateTime.dateTime.getHours(),
minute: customDateTime.dateTime.getMinutes()});
dialog.accepted.connect(function() {
customDateTime.dateTime = new Date(customDateTime.dateTime.getFullYear(),
customDateTime.dateTime.getMonth(),
customDateTime.dateTime.getDate(),
dialog.hour dialog.minute);
});
}
}
}
}
}
It is easy to see that the changes is not much. The property Declaration is replaced with Declaration QML-component CustomDateTime and instead of functions toLocaleDateString() and toLocaleTimeString() uses properties localeDateString and localeTimeString. Throughout the rest of the code is not changed, but now the binding properties. Change the properties on dateTime object CustomDateTime will update all the object properties and properties of localeTimeString in particular that will update the appearance of the object ValueButton.
Opinion
The result was a solution for managing the date, time and information about time zone support components for editing date and time in Sailfish OS. The solution is to create your own QML component and use it as a model. This object allows you to store the date, time and timezone, and also supports binding properties and can be used inside Sailfish OS components DatePickerDialog and TimePickerDailog for editing. The source code of the described example is available in GitHub.
Author: Ivan Shields
Комментарии
Отправить комментарий