/* This file is part of the KDE project Copyright (C) 2006 Jaroslaw Staniek This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kexidatetimeformatter.h" #include #include #include #include #include #include #include #include KexiDateFormatter::KexiDateFormatter() { // use "short date" format system settings //! @todo allow to override the format using column property and/or global app settings TQString df( KGlobal::locale()->dateFormatShort() ); if (df.length()>2) m_separator = df.mid(2,1); else m_separator = "-"; const int separatorLen = m_separator.length(); TQString yearMask("9999"); TQString yearDateFormat("yyyy"), monthDateFormat("MM"), dayDateFormat("dd"); //for setting up m_dateFormat bool ok = df.length()>=8; int yearpos, monthpos, daypos; //result of df.find() if (ok) {//look at % variables //! @todo more variables are possible here, see void KLocale::setDateFormatShort() docs //! http://developer.kde.org/documentation/library/3.5-api/kdelibs-apidocs/kdecore/html/classKLocale.html#a59 yearpos = df.find("%y", 0, false); //&y or %y m_longYear = !(yearpos>=0 && df.mid(yearpos+1, 1)=="y"); if (!m_longYear) { yearMask = "99"; yearDateFormat = "yy"; } monthpos = df.find("%m", 0, true); //%m or %n m_monthWithLeadingZero = true; if (monthpos<0) { monthpos = df.find("%n", 0, false); m_monthWithLeadingZero = false; monthDateFormat = "M"; } daypos = df.find("%d", 0, true);//%d or %e m_dayWithLeadingZero = true; if (daypos<0) { daypos = df.find("%e", 0, false); m_dayWithLeadingZero = false; dayDateFormat = "d"; } ok = (yearpos>=0 && monthpos>=0 && daypos>=0); } m_order = TQDateEdit::YMD; //default if (ok) { if (yearpostimeFormat() ); //m_hourpos, m_minpos, m_secpos; are result of tf.find() TQString hourVariable, minVariable, secVariable; //detect position of HOUR section: find %H or %k or %I or %l m_24h = true; m_hoursWithLeadingZero = true; m_hourpos = tf.find("%H", 0, true); if (m_hourpos>=0) { m_24h = true; m_hoursWithLeadingZero = true; } else { m_hourpos = tf.find("%k", 0, true); if (m_hourpos>=0) { m_24h = true; m_hoursWithLeadingZero = false; } else { m_hourpos = tf.find("%I", 0, true); if (m_hourpos>=0) { m_24h = false; m_hoursWithLeadingZero = true; } else { m_hourpos = tf.find("%l", 0, true); if (m_hourpos>=0) { m_24h = false; m_hoursWithLeadingZero = false; } } } } m_minpos = tf.find("%M", 0, true); m_secpos = tf.find("%S", 0, true); //can be -1 m_ampmpos = tf.find("%p", 0, true); //can be -1 if (m_hourpos<0 || m_minpos<0) { //set default: hr and min are needed, sec are optional tf = "%H:%M:%S"; m_24h = true; m_hoursWithLeadingZero = false; m_hourpos = 0; m_minpos = 3; m_secpos = m_minpos + 3; m_ampmpos = -1; } hourVariable = tf.mid(m_hourpos, 2); m_inputMask = tf; // m_inputMask.replace( hourVariable, "00" ); // m_inputMask.replace( "%M", "00" ); // m_inputMask.replace( "%S", "00" ); //optional m_inputMask.replace( hourVariable, "99" ); m_inputMask.replace( "%M", "99" ); m_inputMask.replace( "%S", "00" ); //optional m_inputMask.replace( "%p", "AA" ); //am or pm m_inputMask += ";_"; m_outputFormat = tf; } KexiTimeFormatter::~KexiTimeFormatter() { delete m_hmsRegExp; delete m_hmRegExp; } TQTime KexiTimeFormatter::stringToTime( const TQString& str ) const { int hour, min, sec; bool pm = false; bool tryWithoutSeconds = true; if (m_secpos>=0) { if (-1 != m_hmsRegExp->search(str)) { hour = m_hmsRegExp->cap(1).toInt(); min = m_hmsRegExp->cap(2).toInt(); sec = m_hmsRegExp->cap(3).toInt(); if (m_ampmpos >= 0 && m_hmsRegExp->numCaptures()>3) pm = m_hmsRegExp->cap(4).stripWhiteSpace().lower()=="pm"; tryWithoutSeconds = false; } } if (tryWithoutSeconds) { if (-1 == m_hmRegExp->search(str)) return TQTime(99,0,0); hour = m_hmRegExp->cap(1).toInt(); min = m_hmRegExp->cap(2).toInt(); sec = 0; if (m_ampmpos >= 0 && m_hmRegExp->numCaptures()>2) pm = m_hmsRegExp->cap(4).lower()=="pm"; } if (pm && hour < 12) hour += 12; //PM return TQTime(hour, min, sec); } TQVariant KexiTimeFormatter::stringToVariant( const TQString& str ) { if (isEmpty( str )) return TQVariant(); const TQTime time( stringToTime( str ) ); if (time.isValid()) return time; return TQVariant(); } bool KexiTimeFormatter::isEmpty( const TQString& str ) const { TQString s(str); return s.replace(':',"").stripWhiteSpace().isEmpty(); } TQString KexiTimeFormatter::timeToString( const TQTime& time ) const { if (!time.isValid()) return TQString(); TQString s(m_outputFormat); if (m_24h) { if (m_hoursWithLeadingZero) s.replace( "%H", TQString::tqfromLatin1(time.hour()<10 ? "0" : "") + TQString::number(time.hour()) ); else s.replace( "%k", TQString::number(time.hour()) ); } else { int time12 = (time.hour()>12) ? (time.hour()-12) : time.hour(); if (m_hoursWithLeadingZero) s.replace( "%I", TQString::tqfromLatin1(time12<10 ? "0" : "") + TQString::number(time12) ); else s.replace( "%l", TQString::number(time12) ); } s.replace( "%M", TQString::tqfromLatin1(time.minute()<10 ? "0" : "") + TQString::number(time.minute()) ); if (m_secpos>=0) s.replace( "%S", TQString::tqfromLatin1(time.second()<10 ? "0" : "") + TQString::number(time.second()) ); if (m_ampmpos>=0) s.replace( "%p", KGlobal::locale()->translate( time.hour()>=12 ? "pm" : "am") ); return s; } //------------------------------------------------ TQString dateTimeInputMask(const KexiDateFormatter& dateFormatter, const KexiTimeFormatter& timeFormatter) { TQString mask(dateFormatter.inputMask()); mask.truncate(dateFormatter.inputMask().length()-2); return mask + " " + timeFormatter.inputMask(); } TQDateTime stringToDateTime( const KexiDateFormatter& dateFormatter, const KexiTimeFormatter& timeFormatter, const TQString& str) { TQString s( str.stripWhiteSpace() ); const int timepos = s.find(" "); const bool emptyTime = timepos >= 0 && timeFormatter.isEmpty(s.mid(timepos+1)); //.replace(':',"").stripWhiteSpace().isEmpty(); if (emptyTime) s = s.left(timepos); if (timepos>0 && !emptyTime) { return TQDateTime( dateFormatter.stringToDate( s.left(timepos) ), timeFormatter.stringToTime( s.mid(timepos+1) ) ); } else { return TQDateTime( dateFormatter.stringToDate( s ), TQTime(0,0,0) ); } } bool dateTimeIsEmpty( const KexiDateFormatter& dateFormatter, const KexiTimeFormatter& timeFormatter, const TQString& str ) { int timepos = str.find(" "); const bool emptyTime = timepos >= 0 && timeFormatter.isEmpty(str.mid(timepos+1)); //s.mid(timepos+1).replace(':',"").stripWhiteSpace().isEmpty(); return (timepos >= 0 && dateFormatter.isEmpty(str.left(timepos)) //s.left(timepos).replace(m_dateFormatter.separator(), "").stripWhiteSpace().isEmpty() && emptyTime); } bool dateTimeIsValid( const KexiDateFormatter& dateFormatter, const KexiTimeFormatter& timeFormatter, const TQString& str ) { int timepos = str.find(" "); const bool emptyTime = timepos >= 0 && timeFormatter.isEmpty(str.mid(timepos+1)); //s.mid(timepos+1).replace(':',"").stripWhiteSpace().isEmpty(); if (timepos >= 0 && dateFormatter.isEmpty(str.left(timepos)) // s.left(timepos).replace(m_dateFormatter.separator(), "").stripWhiteSpace().isEmpty() && emptyTime) //empty date/time is valid return true; return timepos>=0 && dateFormatter.stringToDate( str.left(timepos) ).isValid() && (emptyTime /*date without time is also valid*/ || timeFormatter.stringToTime( str.mid(timepos+1) ).isValid()); }