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.
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:
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
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
Wholesale basketball sneaker trade NFL jersey http://www.b21c.com http://www.tradetan.com
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
wedding dress
Post new comment