Improvements to date formatting support in 4.4

In the past, kdelibs has only officially provided date formatting methods that supported the locale short and long date formats.  A number of apps found this rather restrictive and had to work around it with code like:

KLocale tmpLocale(*KGlobal::locale());
tmpLocale.setDateFormat("%d %b %Y");
QString dateString = tmpLocale.formatDate(aDate);

or worse like:

KLocale tmpLocale(*KGlobal::locale());
tmpLocale.setDateFormat("%d");
QString day = tmpLocale.formatDate(aDate);
tmpLocale.setDateFormat("%b");
QString month = tmpLocale.formatDate(aDate);
tmpLocale.setDateFormat("%Y");
QString year = tmpLocale.formatDate(aDate);
QString text = i18nc("long day number, short month name, long year number",
                     "blah %1 blah %2 blah %3", day, month, year);

or worst of all like:

const QString oldDateFormat = KGlobal::locale()->dateFormat();
KGlobal::locale()->setDateFormat("%Y %m %d");
QString dateString = KGlobal::locale()->formatDate(aDate);
KGlobal::locale()->setDateFormat(oldDateFormat);

(Messing with the global locale is a big no-no, no matter how briefly!  Code disguised to protect the guilty :-)

Well, in 4.4 your code can become a little simpler with native support for ISO date formats, more date component string methods, and a new formatDate() method that directly takes a C/POSIX/GNU standard format string without having to mess with a temp KLocale instance.  This gives a great degree of power over date formatting, but like the saying goes, with great power comes great responsibility, so please use with care and follow a few simple rules.

  1. In the first instance, you should almost always be using the locale Short and Long date formats in your user interface, as these are either the locale standard or the user's preference.
  2. If you do have specific needs in the user interface not covered by the standard formats and need to define your own date format string, then the format string must default to en_US format and must be made translatable to better fit your user's locale, e.g. so our American friends get the month before the day, the rest of us get it in the right order, and Japanese users get Kanji symbols instead of dashes, etc.
  3. If you are writing dates to file or wire, then you need to consider if it is safe to use the global locale to do so, as the Digit Set and Calendar System used may not be what you want, e.g. ODF and RFC both expect Gregorian Calendar System and Arabic Digit Set, but the global locale may be set to something different.  (This also applies to number and money formatting).

So what's changed, and how to use it?

The ISO standard date formats ISO Date (YYYY-MM-DD), ISO Week Date (YYYY-Www-D), and ISO Ordinal Date (YYY-DDD) have become first class citizens alongside the locale/user configurable Short, Long, and Fancy formats.  Use these whenever you want an ISO or RFC standard format date in the locale's Digit Set and Calendar System.

To output an ISO format date:

QDate testDate;
KGlobal::locale()->calendar()->setDate(testDate, 2009, 12, 1);
QString stringDate;
stringDate = KGlobal::locale()->formatDate(testDate, KLocale::IsoDate);        // "2009-12-01"
stringDate = KGlobal::locale()->formatDate(testDate, KLocale::IsoWeekDate);    // "2009-W49-2"
stringDate = KGlobal::locale()->formatDate(testDate, KLocale::IsoOrdinalDate); // "2009-335"

To read in an ISO format date from a string:

testDate = KGlobal::locale()->readDate("2009-12-01", KLocale::IsoFormat);
testDate = KGlobal::locale()->readDate("2009-W49-2", KLocale::IsoWeekFormat);
testDate = KGlobal::locale()->readDate("2009-335",   KLocale::IsoOrdinalFormat);

To directly set a date using the ISO Week and Ordinal dates:

KGlobal::locale()->calendar()->setDateIsoWeek(testDate, 2009, 49, 2); // Year, Week, Weekday
KGlobal::locale()->calendar()->setDate(testDate, 2009, 335);          // Year, Day of Year

To validate a ISO Week or Ordinal date:

KGlobal::locale()->calendar()->isValidIsoWeek(2009, 49, 2); // Year, Week, Weekday
KGlobal::locale()->calendar()->isValid(2009, 335);          // Year, Day of Year

The existing readDate() format string method has also been extended to read the ISO Week and Ordinal date components in any order or format:

testDate = KGlobal::locale()->readDate("Day 2 of Week 49, 2009", "Day %u of Week %V, %Y");
testDate = KGlobal::locale()->readDate("335/2009",   "%j/%Y");

Note that historically readDate() is not strict in applying the format string and will make best efforts to interpret the users input while obeying the input order, i.e. extra spaces are ignored, if the format string has long month it will accept the short month if entered instead, and vice versa.  I might implement a strict mode if there is demand.

If you just need a single date component as a string, such as day number or month name, in long or short format, then simply use the appropriate existing or new string method which will return the component in the users Calendar System and Language or Digit Set:

monthName()
weekDayName()
yearString()
monthString()
dayString()
dayOfYearString()    // New
dayOfWeekString()    // New
weekNumberString()   // New
monthsInYearString() // New
weeksInYearString()  // New
daysInYearString()   // New
daysInMonthString()  // New
daysInWeekString()   // New

To output a single date component:

stringDate = KGlobal::locale()->calendar()->monthName(testDate, KCalendarSystem::ShortName); // "Dec"
stringDate = KGlobal::locale()->calendar()->monthName(testDate, KCalendarSystem::LongName);  // "December"
stringDate = KGlobal::locale()->calendar()->dayString(testDate, KCalendarSystem::ShortFormat); // "1"
stringDate = KGlobal::locale()->calendar()->dayString(testDate, KCalendarSystem::LongFormat);  // "01"

Only if none of these options will meet your requirements should you use the new KCalendarSystem::dateFormat() routine.  Please read the extensive apidox for all the options available, but it supports most of the C / POSIX standard component codes as well as the GNU extensions for modifying the padding character and the padding width.  Note that a couple of the historic KDE format codes differ from the C/POSIX standard, in future I may add a fully compatible mode.

In use you should almost always translate the format string and include the kdedt-format keyword in the context:

QDate reportDate;
KGlobal::locale()->calendar()->setDate(reportDate, reportYear, reportMonth, 1);
dateFormat = i18nc("(kdedt-format) Report month and year in report header", "%B %Y"));
dateString = KGlobal::locale()->calendar()->formatDate(reportDate, dateFormat);

If you have to write dates to file or wire in a standard interchange format that always requires requires Gregorian and Arabic digits, then the easiest solution is to use QDate directly:

QString standardDateString = QDate.toString(Qt::ISODate);
or
QString standardDateString = QDate.toString("yyyy-MM-dd");

Alternatively, use the temp KLocale trick, but be very careful about just copying the global locale to start with, it's probably better to create a default one from scratch:

KLocale *standardLocale = new KLocale(yourCatalog, "en_US", "us");
standardLocale->setDateFormat("%a, %d %b %Y");
standardLocale->setDateFormatShort("%Y-%m-%d");

Note that reading in numbers and dates in any Digit Set is seamless, it's just writing them out you need to think about.

In general, if you write dates and numbers to file or wire, you may want to write unit tests to check your code still works with an alternative Digit Set and Calendar System set in the global locale.  If you use KMime's DateFormatter class for ISO and RFC dates then you should be OK.

The sharp-witted out there would have two thoughts going through their mind about the plea to always translate your date format strings:

  1. Why expose the full date formats for possible abuse when you could restrict the options using some format enum flags like formatTime() does and get invisible localisation as a result?
  2. Isn't language translation a poor heuristic for locale date format?  What about a Spanish-speaking American who will get the wrong format?

Well, we did look at using enums, but there were just too many variables to make it work simply without giving the translators hundreds of pre-defined strings to do, and it still wouldn't meet all the use case (see the reviewboard).  In the end it is better to trust people and encourage them to use the tools properly than to try impose restrictions they will just work-round anyway. And yes, it is a poor heuristic, but it affects fewer people than not translating at all. For 4.5 I am looking into a scheme to fully define the different rule sets for date formatting (e.g. American, International, European, ISO, Japanese, etc) and include these in each locale file to allow fully automatic construction of the format strings from enums with no pre- or post-translation required, but I'm not convinced it's possible or worth the effort for the few use cases we have so far.

I'll copy most of this onto TechBase for future reference.

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

This is a really good

This is a really good article and thank you for sharing this with us.
short wedding dresses
bridal wedding gowns
plus size wedding gowns

B21C

answer this topic

I opine that to receive the loans from banks you ought to have a good motivation. But, once I have received a bank loan, because I was willing to buy a car.

wedding dress

reply

Your knowledge related to this post is professional and lots of scholars can utilize this for their doctoral thesis. But some of people permanently utilize the support of the dissertation writing service.

reply this post

Students at shool are willing to get the good grade and they purchase the already written essays connected with this good post from the writing services, and from time to time they need the topics just about buy research paper.

re

Such good buy dissertation like this good topic is the thing that people would like purchase from the thesis writers, thence some times they have the thesis writing service and custom writing.

reply this post

This is what I was looking for a while! Thank you for this topic just about study! Once somebody state that In union there is effect. Our high qualified crew can assist you in writing term papers.

big boobs

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Post new comment

The content of this field is kept private and will not be shown publicly.