Главная » XSLT » Форматирование даты и времени

0

Задача

Требуется отформатировать дату и время в соответствии с заданной формат­ной строкой.

Решение

Мы повторно используем многие ранее разработанные в этой главе шаблоны. В шаблоне format-date-time спецификаторы формата имеют вид %x (см. ниже), а прочие символы выводятся буквально. По умолчанию подразумевается формат ISO для даты и времени по григорианскому календарю.

<xsl:template name="ckbk:format-date-time"> <xsl:param name="year"/> <xsl:param name="month"/> <xsl:param name="day"/> <xsl:param name="hour"/> <xsl:param name="minute"/> <xsl:param name="second"/> <xsl:param name="time-zone"/>

<xsl:param name="format" select="’%Y-%m-%dT%H:%M:%S%z’"/>

<xsl:choose>

<xsl:when test="contains($format, ‘%’)">

<xsl:value-of select="substring-before($format, ‘%’)"/> </xsl:when>

<xsl:otherwise>

<xsl:value-of select="$format"/> </xsl:otherwise> </xsl:choose>

<xsl:variable name="code"

select="substring(substring-after($format, ‘%’), 1, 1)"/>

<xsl:choose>

<!– Сокращенное название дня недели –> <xsl:when test="$code=’a’">

<xsl:variable name="day-of-the-week">

<xsl:call-template name="ckbk:calculate-day-of-the-week"> <xsl:with-param name="year" select="$year"/> <xsl:with-param name="month" select="$month"/> <xsl:with-param name="day" select="$day"/> </xsl:call-template> </xsl:variable>

<xsl:call-template name="ckbk:get-day-of-the-week-abbreviation"> <xsl:with-param name="day-of-the-week" select="$day-of-the-week"/> </xsl:call-template> </xsl:when>

<!– Полное название дня недели –> <xsl:when test="$code=’A’">

<xsl:variable name="day-of-the-week">

<xsl:call-template name="ckbk:calculate-day-of-the-week"> <xsl:with-param name="year" select="$year"/> <xsl:with-param name="month" select="$month"/> <xsl:with-param name="day" select="$day"/> </xsl:call-template> </xsl:variable>

<xsl:call-template name="ckbk:get-day-of-the-week-name"> <xsl:with-param name="day-of-the-week"

select="$day-of-the-week"/> </xsl:call-template> </xsl:when>

<!– Сокращенное название месяца –> <xsl:when test="$code=’b’">

<xsl:call-template name="ckbk:get-month-abbreviation">

<xsl:with-param name="month" select="$month"/> </xsl:call-template>

</xsl:when>

<!– Полное название месяца –> <xsl:when test="$code=’B’">

<xsl:call-template name="ckbk:get-month-name">

<xsl:with-param name="month" select="$month"/> </xsl:call-template> </xsl:when>

<!— Представление даты и времени в текущей локали —> <xsl:when test="$code=’c’">

<xsl:text>[не реализовано]</xsl:text> </xsl:when>

<!— День месяца в виде десятичного числа (01 – 31) —> <xsl:when test="$code=’d’">

<xsl:value-of select="format-number($day,’0 0′)"/> </xsl:when>

<!– Час в 24-часовом формате (00 – 23) –> <xsl:when test="$code=’H’">

<xsl:value-of select="format-number($hour,’00’)"/> </xsl:when>

<!– Час в 12-часовом формате (01 – 12) –> <xsl:when test="$code=’I’"> <xsl:choose>

<xsl:when test="$hour = 0">12</xsl:when> <xsl:when test="$hour &lt; 13">

<xsl:value-of select="format-number($hour,’00’)"/> </xsl:when> <xsl:otherwise>

<xsl:value-of select="format-number($hour – 12,’00’)"/> </xsl:otherwise> </xsl:choose> </xsl:when>

<!— День года в виде десятичного числа (001 – 366) —> <xsl:when test="$code=’j’"> <xsl:variable name="diff"> <xsl:call-template name="ckbk:date-difference">

<xsl:with-param name="from-year" select="$year"/> <xsl:with-param name="from-month" select="1"/> <xsl:with-param name="form-day" select="1"/>

<xsl:with-param name="to-year" select="$year"/> <xsl:with-param name="to-month" select="$month"/> <xsl:with-param name="to-day" select="$day"/> </xsl:call-template> </xsl:variable>

<xsl:value-of select="format-number($diff + 1, ‘000’)"/> </xsl:when>

<!— Номер месяца в виде десятичного числа (01 – 12) —> <xsl:when test="$code=’m’">

<xsl:value-of select="format-number($month,’0 0′)"/> </xsl:when>

<!– Минута в виде десятичного числа (00 – 59) –> <xsl:when test="$code=’M’">

<xsl:value-of select="format-number($minute,’0 0′)"/> </xsl:when>

<!– Индикатор A.M./P.M. в текущей локали для времени в 12-часовом формате –>

<xsl:when test="$code=’p’"> <xsl:choose>

<xsl:when test="$hour &lt; 12">AM</xsl:when> <xsl:otherwise>PM</xsl:otherwise> </xsl:choose> </xsl:when>

<!– Секунда в виде десятичного числа (00 – 59) –> <xsl:when test="$code=’S’">

<xsl:value-of select="format-number($second,’00’)"/> </xsl:when>

<!– Номер недели в году в виде десятичного числа, когда неделя начинается с воскресенья (00 – 53) –> <xsl:when test="$code=’U’"> <!– add 1 to day — >

<xsl:call-template name="ckbk:calculate-week-number"> <xsl:with-param name="year" select="$year"/> <xsl:with-param name="month" select="$month"/> <xsl:with-param name="day" select="$day + 1"/> </xsl:call-template> </xsl:when>

<!— День недели в виде десятичного числа (0 – 6; воскресенье – 0) —> <xsl:when test="$code=’w’">

<xsl:call-template name="ckbk:calculate-day-of-the-week"> <xsl:with-param name="year" select="$year"/> <xsl:with-param name="month" select="$month"/> <xsl:with-param name="day" select="$day"/> </xsl:call-template> </xsl:when>

<!– Номер недели в году в виде десятичного числа, когда неделя начинается с понедельника (00 – 53) –> <xsl:when test="$code=’W’">

<xsl:call-template name="ckbk:calculate-week-number"> <xsl:with-param name="year" select="$year"/> <xsl:with-param name="month" select="$month"/> <xsl:with-param name="day" select="$day"/> </xsl:call-template> </xsl:when>

<!– Представление даты в текущей локали –> <xsl:when test="$code=’x’">

<xsl:text>[не реализовано]</xsl:text> </xsl:when>

<!– Представление времени в текущей локали –> <xsl:when test="$code=’X’">

<xsl:text>[не реализовано]</xsl:text> </xsl:when>

<!— Год без века в виде десятичного числа (00 – 99) –> <xsl:when test="$code=’y’">

<xsl:value-of select="format-number($year mod 100,’00’)"/> </xsl:when>

<!– Год с веком в виде десятичного числа –> <xsl:when test="$code=’Y’">

<xsl:value-of select="format-number($year,’0000′)"/> </xsl:when>

<!– Название или аббревиатура часового пояса; –>

<!– если часовой пояс неизвестен, ничего не выводится –>

<xsl:when test="$code=’z’">

<xsl:value-of select="$time-zone"/> </xsl:when>

<xsl:when test="$code=’%’">

<xsl:text>%</xsl:text> </xsl:when>

</xsl:choose>

<xsl:variable name="remainder"

select="substring(substring-after($format, ‘%’), 2)"/>

<xsl:if test="$remainder">

<xsl:call-template name="ckbk:format-date-time"> <xsl:with-param name="year" select="$year"/> <xsl:with-param name="month" select="$month"/> <xsl:with-param name="day" select="$day"/> <xsl:with-param name="hour" select="$hour"/> <xsl:with-param name="minute" select="$minute"/> <xsl:with-param name="second" select="$second"/> <xsl:with-param name="time-zone" select="$time-zone"/> <xsl:with-param name="format" select="$remainder"/> </xsl:call-template> </xsl:if>

</xsl:template>

<xsl:template name="ckbk:format-julian-day"> <xsl:param name="julian-day"/>

<xsl:param name="format" select="’%Y-%m-%d’"/>

<xsl:variable name="a" select="$julian-day + 32044"/> <xsl:variable name="b" select="floor((4 * $a + 3) div 146097)"/> <xsl:variable name="c" select="$a – floor(($b * 146097) div 4)"/>

<xsl:variable name="d" select="floor((4 * $c + 3) div 1461)"/> <xsl:variable name="e" select="$c – floor((1461 * $d) div 4)"/> <xsl:variable name="m" select="floor((5 * $e + 2) div 153)"/>

<xsl:variable name="day" select="$e – floor((153 * $m + 2) div 5) + 1" <xsl:variable name="month" select="$m + 3 – 12 * floor($m div 10)"/> <xsl:variable name="year" select="$b * 100 + $d – 4800 + floor($m div 10)’

<xsl:call-template name="ckbk:format-date-time"> <xsl:with-param name="year" select="$year"/> <xsl:with-param name="month" select="$month"/> <xsl:with-param name="day" select="$day"/> <xsl:with-param name="format" select="$format"/>

</xsl:call-template> </xsl:template>

XSLT 2.0

Воспользуемся встроенными функциями форматирования даты. В следую­щем фрагменте предполагается, что дата представлена строкой вида ГГГГММДД, что зачастую удобнее на практике, чем формат ISO, которого ожидает функция

format-date:

<xsl:param name="date" as="xs:string"/>

<invoiceDate><xsl:value-of select="format-date(

xs:date(concat(substring($date,1,4),

substring($date,5,2),

substring($date,7,2))), ‘[MNn] [D01, [Y0 0 01′)"/></invoiceDate>

Для даты $date = ‘20050811’ мы получим

<invoiceDate>August 11, 2 0 05</invoiceDate>

Обсуждение

XSLT 1.0

В этом примере мы воспользовались плодами работы, проделанной в преды­дущих рецептах. Те виды форматирования, в которых участвует локаль, остались нереализованными, но это можно исправить с помощью функций расширения (см. главу 12).

XSLT 2.0

Чтобы вам было удобнее, приведу выдержку из спецификации W3C. Предоставляются три функции для представления даты и времени в виде строк с учетом выбранного календаря и локали. У каждой функции есть два варианта:

format-dateTime($value as xs:dateTime?, $picture as xs:string,

$date-format-name as xs:string) as xs:string?

format-dateTime($value as xs:dateTime?, $picture as xs:string) as xs:string?

format-date($value as xs:date?, $picture as xs:string,

$date-format-name as xs:string) as xs:string?

format-date($value as xs:date?, $picture as xs:string) as xs:string?

format-time($value as xs:time?, $picture as xs:string,

$date-format-name as xs:string) as xs:string?

format-time($value as xs:time?, $picture as xs:string) as xs:string?

Функции format-dateTime, format-date и format-time форматируют значение $value в виде строки, используя форматную строку, заданную аргу­ментом $picture, и именованный формат даты, заданный аргументом $date- format-name, или формат даты по умолчанию, если последний аргумент опу­щен. Результатом функции является форматированное строковое представление аргумента dateTime, date или time.

Все три функции format-dateTime, format-date и format-time соби­рательно называются функциями форматирования даты.

Если имя, заданное аргументом $date-format-name, не является допусти­мым QName или его префикс не был объявлен в объявлении пространства имен, попадающего в область видимости, или таблица стилей не содержит объявления date-format с подходящим expanded-QName, возникает динамическая ошиб­ка. Процессор должен либо известить об этой ошибке, либо исправить ее, проиг­норировав аргумент $date-format-name. Если процессор способен обнару­жить ошибку статически (например, в случае, когда аргумент представляет собой строковый литерал), то он может дополнительно известить о статической ошибке.

Если $value – пустая последовательность, то возвращается пустая последо­вательность.

Объявление элемента date-format

<!– Категория: объявление –>

<xsl:date-format name = qname language = nmtoken calendar = qname />

Элемент xsl:date-format объявляет формат даты (date-format), кото­рый предоставляет информацию, используемую функциями форматирования даты. Если атрибут name указан, то элемент объявляет именованный формат даты, в противном случае – формат даты по умолчанию. Значением атрибута name является QName. Статической ошибкой считается объявление формата даты по умолчанию или формата с одним и тем же именем более одного раза (даже с разным приоритетом импорта), если только в каждом объявлении значе­ния всех атрибутов не оказываются в точности одинаковыми (принимая во вни­мание и значения по умолчанию). Если в таблице стилей нет объявления форма­та даты по умолчанию, то подразумевается объявление, эквивалентное элементу xsl:date-format без каких-либо атрибутов.

Атрибут language задает язык для строки, возвращаемой функцией format- date. Он должен принимать значение, допустимое для атрибута xml:lang. Если этот атрибут опущен, то значение по умолчанию зависит от реализации.

Атрибут language используется для выбора следующих зависящих от языка аспектов:

?               названий (например, месяцев);

?               формы записи чисел;

?               соглашения о представлении часа (0-23 или 1-24, 0-11 или 1-12);

?               первого дня недели, первой недели месяца.

Набор поддерживаемых языков зависит от реализации.

Атрибут calendar определяет календарь, в который должны быть преобра­зованы значения аргумента $value типа dateTime, date или time, и соглаше­ния, применяемые к результирующей строке.

Значение calendar должно быть допустимым квалифицированным именем QName. Если QName не содержит префикса, то подразумевается календарь с од­ним из описанных ниже обозначений. Если QName содержит префикс, то QName расширяется в expanded-QName, и expanded-QName определяет календарь; пове­дение в этом случае настоящим документом не определено.

Если атрибут calendar опущен, используется значение, определяемое локалью.

Статической ошибкой считается ситуация, когда реализация не поддерживает язык, заданный атрибутом language, или календарь, заданный атрибутом calendar, или то и другое одновременно. Процессор должен либо известить об этой ошибке, либо исправить ее, выбрав вместо указанного зависящее от локали значение того или друго­го атрибута. Если в итоге будет использован не тот календарь, который был запрошен, то в результирующую строку должно быть включено название календаря.

Перечисленные ниже календари используются последние несколько сотен ® лет. В прошлом употреблялись и другие календари, которые во многих слу­чаях невозможно поддержать без дополнительных параметров. Такие пара­метры можно определить с помощью дополнительных атрибутов элемента xsl:date-format, квалифицированных префиксом пространства имен. Се­мантика подобных атрибутов не определяется настоящей спецификацией.

В настоящей спецификации не определяется ни один из перечисленных ка­лендарей, а также способы их отображения на пространство значений типа дан­ных xs:date в терминах XML Schema. Существует лишь приближенная эквивален­тность между датами, представленными в различных календарях. Например, в разных календарях день начинается не в один и тот же момент, начало дня может также зависеть от географического местоположения. Поэтому реализа­ции, поддерживающие не только григорианский календарь, могут давать раз­личные результаты.

Обозначение

Календарь

AD

Anno Domini (христианская эра)

AH

Anno Hegirae (эра Хиджры)

 

Обозначение

Календарь

AME

Mauludi Era (количество солнечных лет с момента рождения Мухаммада)

AM

Anno Mundi (еврейская эра от «сотворения мира»)

AP

Anno Persici (персидская эра)

AS

Aji Saka Era (эра Аджи Сака, остров Ява)

BE

Buddhist Era (буддийская эра)

CB

Cooch Behar (эра Кач-Бехар)

CE

Common Era (эра «от рождества Христова»)

CL

Chinese Lunar Era (китайская лунная эра)

CS

Chula Sakarat Era (эра Чула Сакарат, Юго-Восточная Азия)

EE

Ethiopean Era (эфиопская эра)

FE

Fasli Era (эра Фасли)

ISO

календарь ISO 8601

JE

японский календарь

KE

Khalsa Era (сикхский календарь)

KY

Kali Yuga (эра Кали-юга, Индия)

ME

Malabar Era (малабарская эра)

MS

Monarchic Solar Era

NS

Nepal Samwat Era (эра Самвата, Непал)

OS

Old Style («старый стиль», юлианский календарь)

RS

Rattanakosin Era (эра Раттанакосина, Бангкок)

SE

Saka Era (эра Сака, Индия)

SH

мусульманская солнечная эра

SS

эра Сака-Самват

TE

Tripurabda Era (эра Трипури)

VE

Vikrama Era (эра Викрамы)

VS

Vikrama Samvat Era (эра Викрама-Самват)

Должен поддерживаться хотя бы один из перечисленных выше календарей. Какие именно календари поддерживаются, зависит от реализации.

Включенный в список календарь ISO 8601, обозначаемый ISO, по существу не отличается от григорианского календаря AD, но предписывает четко опре­деленные соглашения о нумерации, определенные в стандарте ISO 8601, не подверженные локализации. Точнее, в календаре ISO дни недели нумеруются с 1 (понедельник) по 7 (воскресенье), а первой неделей года считается неделя (с понедельника по воскресенье), содержащая первый четверг года. Числовые значения года, месяца, дня, часа, минуты и секунды в этом календаре такие же, как в лексическом представлении даты и времени, определенном в специфика­ции XML Schema. Календарь ISO предназначен в первую очередь для прило­жений, которые порождают дату и время в формате, пригодном для экспорта в другие приложения, а не для человека.

Пространство значений типов данных для даты и времени, определенное ® в спецификации XML Schema, основано на абсолютных моментах времени. Лексическое пространство для этих типов данных определяет представление абсолютных моментов времени с помощью пролептического григорианского календаря, то есть современного западного календаря, экстраполированного

в прошлое и будущее, однако пространство значений от календаря не зависит. Функции форматирования даты порождают представление од­ной и той же абсолютной временной точки в указанном календаре. Так, например, дата, лексическое представление которой в соответствии с XML Schema равно 1502-01-11 (день рождения папы Григория XIII), в кален­даре Old Style (юлианском) может быть представлена как 1 January 1502. Это отражает тот факт, что между григорианским и юлианским календа­рями есть разница в десять дней. Было бы неправильно (и привело бы к неправильным результатам) представлять эту дату в элементе или ат­рибуте типа xs:date как 1502-01-01, пусть даже именно так она записывается в современных документах.

Форматная строка

Форматная строка состоит из последовательности специальных марке­ров и литеральных подстрок. Подстрока, заключенная в фигурные скобки, интерпретируется как маркер; подстроки, находящиеся вне квадратных ско­бок, считаются литеральными. Литеральные подстроки могут отсутствовать, а если имеются, то выводятся без изменения, в том числе со всеми пропуска­ми. Если внутри литеральной подстроки встречается открывающая или зак­рывающая квадратная скобка, она должна быть повторена дважды. Вместо маркеров в результирующую строку подставляются строки, описывающие те или иные аспекты форматируемой даты или времени. Маркеры подробно описаны ниже.

Маркер состоит из спецификатора компонента, за которым может следовать один или два модификатора представления и/или необязательный модификатор длины. Любые пробелы внутри маркера игнорируются.

Спецификатор компонента обозначает нужный компонент даты или времени и может принимать следующие значения:

Динамической ошибкой считается ситуация, когда спецификатор компонента в форматной строке ссылается на компоненты, отсутствующие в переданном па­раметре $value или не поддерживаемые выбранным календарем. Это исправи­мая ошибка. Процессор может известить об ошибке или исправить ее, проигнори­ровав некорректные спецификаторы компонентов.

Первый модификатор представления определяет стиль представления значе­ния компонента и может принимать следующие значения:

Любой символ с десятичным значением 1 (в смысле кодировки Unicode) генери­рует десятичное представление числа с помощью подходящего набора цифр Unicode.

Любой другой символ можно использовать для указания последовательности нумерации, начинающейся в этого символа, если реализация поддерживает такую последовательность нумерации.

Если реализация не поддерживает указанный модификатор представления, то вместо него должен использоваться модификатор представления, подразуме­ваемый по умолчанию для данного компонента.

Если первый модификатор представления присутствует, то за ним может следовать второй модификатор представления, который может принимать сле­дующие значения:

Вне зависимости от того, включен ли модификатор представления, можно указать модификатор ширины. Он говорит о том, сколько символов или цифр должно быть в представлении значения.

Модификатор ширины имеет вид:

min-width ("-" max-width)?

где min-width – либо целое без знака, обозначающее минимальное число выво­димых символов, либо символ *, говорящий о том, что минимум явно не задан, а max-width – либо целое без знака, обозначающее максимальное число выводи­мых символов, либо символ *, говорящий о том, что максимум явно не задан. Если часть max-width опущена, подразумевается *. Оба целых числа, если они при­сутствуют, должны быть положительны.

Если модификатор ширины не задан, то выводится столько символов, сколько необходимо для представления значения компонента без обрезания и дополне­ния; результат называется полным представлением значения.

Если число символов в полном представлении превышает заданную макси­мальную ширину, то рекомендуется, чтобы процессор подыскал альтернатив­ное более короткое представление, которое уместилось бы в заданную макси­мальную ширину. Если модификатор представления равен n или N, то это достигается сокращением имени либо путем использования общепринятой аб­бревиатуры, либо путем отбрасывания символов справа. Так, если max-width равно 4, то следует брать четырехбуквенные аббревиатуры, но использование трехбуквенных тоже допустимо, если таково стандартное соглашение. (На­пример, «Tuesday» можно сократить до «Tues», а «Friday» – до «Fri».) В случае компонента «год» задание max-width означает, что нужно опустить старшие цифры года; например, если max-width равно 2, то год 2003 должен быть вы­веден как 03. Если не существует способа уместить значение в заданную мак­симальную ширину (например, при использовании римских цифр), должно выводиться полное представление значения.

Если полное представление значения короче заданной минимальной шири­ны, то рекомендуется, чтобы процессор дополнил значение до заданной ширины. В случае десятичного представления числа это следует делать путем дописыва­ния в начало нулей из подходящего набора символов. В остальных случаях в начало дописываются пробелы.

 

Выбор названий и сокращений для заданного языка зависит от реализации. На­пример, в одной реализации название месяца July (июль) может сокращаться до Jul, а в другой – до Jly. В случае немецкого языка суббота может называться как Samstag, так и Sonnabend. Реализация может предоставлять механизмы, позволяющие пользо­вателю управлять выбором названия или аббревиатуры в таких случаях.

В примерах ниже показаны варианты форматирования даты и времени. Предполагается, что используется григорианский календарь и что значение атрибута name в объявлении xsl:date-format в таблице стилей такое же, как значение атрибута language. (Например, <date-format name="sv" language="sv"/>.)

В следующих примерах используются не-григорианские календари.

<!– Пpимep: тайский Kane^apb –>

<xsl:date-format name="modern_Thai" language="th" calendar="BE"/> format-date($d, "[D&#x0E51;] [Mn] [Y&#x0E51;]", "modern_Thai") <!– Результат:

<!– Пpимep: исламский кaлeндapь –>

<xsl:date-format name="Islamic" language="ar" calendar="AH"/> format-date($d, "[D&#x0661;] [Mn] [Y&#x0661;]", "Islamic")

<!– Результат:–>

<!– Пpимep: eвpeйcкий кaлeндapь –>

<xsl:date-format name="Jewish" language="he" calendar="AM"/> format-date($d, "[D] [Mn] [Y]", "Jewish") <!– Результат: 2 657 63 –>

Мангано Сэл  XSLT. Сборник рецептов. – М.: ДМК Пресс, СПБ.: БХВ-Петербург, 2008. – 864 с.: ил.

По теме:

  • Комментарии