Add timezone_from_id, timezone_id expression functions

These functions allow creating a timezone from a IANA time zone
database ID, or extracting the IANA ID from a timezone object
respectively.
This commit is contained in:
Nyall Dawson 2025-07-23 09:04:14 +10:00
parent 47e8c46d03
commit b6173ac2ef
4 changed files with 68 additions and 0 deletions

View File

@ -0,0 +1,15 @@
{
"name": "timezone_from_id",
"type": "function",
"groups": ["Conversions", "Date and Time"],
"description": "Creates a timezone object from a string ID (from the IANA timezone database). The ID must be one of the available system IDs or a valid UTC-with-offset ID.",
"arguments": [{
"arg": "id",
"description": "string containing the time zone ID"
}],
"examples": [{
"expression": "timezone_from_id('Australia/Brisbane')",
"returns": "AEST timezone object"
}],
"tags": ["time", "zone", "date", "datetime", "offset", "utc"]
}

View File

@ -0,0 +1,15 @@
{
"name": "timezone_id",
"type": "function",
"groups": ["Conversions", "Date and Time"],
"description": "Returns the ID string for a timezone object, using IDs from the IANA timezone database.",
"arguments": [{
"arg": "timezone",
"description": "a valid timezone object"
}],
"examples": [{
"expression": "timezone_id(timezone_from_id('Australia/Brisbane'))",
"returns": "'Australia/Brisbane'"
}],
"tags": ["time", "zone", "date", "datetime", "offset", "utc"]
}

View File

@ -1359,6 +1359,34 @@ static QVariant fcnMakeDateTime( const QVariantList &values, const QgsExpression
return QVariant( QDateTime( date, time ) );
}
static QVariant fcnTimeZoneFromId( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
const QString timeZoneId = QgsExpressionUtils::getStringValue( values.at( 0 ), parent );
QTimeZone tz;
if ( !timeZoneId.isEmpty() )
{
tz = QTimeZone( timeZoneId.toUtf8() );
}
if ( !tz.isValid() )
{
parent->setEvalErrorString( QObject::tr( "'%1' is not a valid time zone ID" ).arg( timeZoneId ) );
return QVariant();
}
return QVariant::fromValue( tz );
}
static QVariant fcnTimeZoneToId( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
const QTimeZone timeZone = QgsExpressionUtils::getTimeZoneValue( values.at( 0 ), parent );
if ( timeZone.isValid() )
{
return QString( timeZone.id() );
}
return QVariant();
}
static QVariant fcnMakeInterval( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
{
const double years = QgsExpressionUtils::getDoubleValue( values.at( 0 ), parent );
@ -8647,6 +8675,8 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
<< QgsExpressionFunction::Parameter( QStringLiteral( "minutes" ), true, 0 )
<< QgsExpressionFunction::Parameter( QStringLiteral( "seconds" ), true, 0 ),
fcnMakeInterval, QStringLiteral( "Date and Time" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "timezone_from_id" ), { QgsExpressionFunction::Parameter( QStringLiteral( "id" ) ) }, fcnTimeZoneFromId, QStringLiteral( "Date and Time" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "timezone_id" ), { QgsExpressionFunction::Parameter( QStringLiteral( "timezone" ) ) }, fcnTimeZoneToId, QStringLiteral( "Date and Time" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "lower" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnLower, QStringLiteral( "String" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "upper" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnUpper, QStringLiteral( "String" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "title" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ), fcnTitle, QStringLiteral( "String" ) )

View File

@ -2052,6 +2052,14 @@ class TestQgsExpression : public QObject
QTest::newRow( "formatted string from date with language" ) << "format_date('2019-06-29','d MMMM yyyy','fr')" << false << QVariant( QString( "29 juin 2019" ) );
QTest::newRow( "formatted string with Z" ) << "format_date(to_datetime('2019-06-29T13:34:56+01:00'),'yyyy-MM-ddTHH:mm:ssZ')" << false << QVariant( QString( "2019-06-29T12:34:56Z" ) );
// time zone functions
QTest::newRow( "timezone_from_id NULL" ) << "timezone_from_id(NULL)" << false << QVariant();
QTest::newRow( "timezone_from_id not string" ) << "timezone_from_id(123)" << true << QVariant();
QTest::newRow( "timezone_from_id invalid id" ) << "timezone_from_id('xxxx')" << true << QVariant();
QTest::newRow( "timezone_id NULL" ) << "timezone_id(NULL)" << false << QVariant();
QTest::newRow( "timezone_id not timezone" ) << "timezone_id(123)" << true << QVariant();
QTest::newRow( "timezone_id valid timezone" ) << "timezone_id(timezone_from_id('Australia/Brisbane'))" << false << QVariant( QString( "Australia/Brisbane" ) );
// Color functions
QTest::newRow( "ramp color" ) << "ramp_color('Spectral',0.3)" << false << QVariant( "253,190,116,255" );
QTest::newRow( "ramp color error" ) << "ramp_color('NotExistingRamp',0.3)" << true << QVariant();