П О Р Т А Л                            
С Е Т Е В Ы Х                          
П Р О Е К Т О В                        
  
Поиск по сайту:
                                                 
Главная

О проекте

Web-мастеру
     HTML & JavaScript
     SSI
     Perl
     PHP
     XML & XSLT
     Unix Shell

MySQL

Безопасность

Хостинг

Другое








Самое читаемое:

Учебник PHP - "Для Чайника".
Просмотров 3409 раз(а).

Иллюстрированный самоучитель по созданию сайтов.
Просмотров 5958 раз(а).

Учебник HTML.
Просмотров 3202 раз(а).

Руководство по PHP5.
Просмотров 5418 раз(а).

Хостинг через призму DNS.
Просмотров 4018 раз(а).

Подборка текстов стандартных документов.
Просмотров 55710 раз(а).

Учебник PHP - Самоучитель
Просмотров 2995 раз(а).

Документация на MySQL (учебник & справочное руководство)
Просмотров 4569 раз(а).

Внешние атаки...
Просмотров 3732 раз(а).

Учебник PHP.
Просмотров 2767 раз(а).

SSI в примерах.
Просмотров 37384 раз(а).



 
 
| Добавить в избранное | Сделать стартовой | Помощь





Руководство пользователя для GNU Awk

15. Библиотека функций awk

15.7 Превращения дат в отметки времени

Функция systime, встроенная в gawk, возвращает текущее время дня как отметку времени в секундах от начала века. Эта отметка может быть превращена в пригодную для печати дату в одном из множества форматов с помощью встроенной функции strftime. (Подробности о systime и strftime см. в разделе 12.5 [Функции для действий с отметками времени], стр. 148.)

Интересную и трудную проблему представляет превращение читаемого представления обратно в отметку времени. Библиотека ANSI Cи имеет функцию mktime, которая делает основную работу превращения канонического представления даты в отметку времени. С первого взгляда может показаться, что gawk должна иметь встроенную функцию mktime, которая копирует версию языка Си.

Приведем версию mktime для awk. Она берет простое представление даты и времени и сворачивает их в метку времени. Код, представленный здесь, перемешан с словесными пояснениями. В разделе 16.2.7 [Извлечение программ из файлов Texinfo Source], стр. 238, вы увидите, как должен обрабатываться файл Texinfo source этой книги для извлечения кода в отдельный исходный файл.

Программа начинается с описывающего комментария и правила BEGIN, которое инициализирует таблицу .tm.months. Эта таблица есть двумерный массив, содержащий длины месяцев. Первый индекс есть 0 для регулярных годов и 1 для високосных. Значения длин одинаковы для годов обоих типов, за исключением Февраля; поэтому нужно использовать кратное присваивание.

# mktime.awk --- преобразует каноническое представление даты
# в отметку времени# Arnold Robbins, arnold@gnu.org, Public Domain # May 1993
BEGIN " -
# Инициализация таблицы длин месяцев
.tm.months[0,1] = .tm.months[1,1] = 31 .tm.months[0,2] = 28;
.tm.months[1,2] = 29 .tm.months[0,3] = .tm.months[1,3] = 31
.tm.months[0,4] = .tm.months[1,4] = 30 .tm.months[0,5] = .tm.months[1,5] = 31
.tm.months[0,6] = .tm.months[1,6] = 30 .tm.months[0,7] = .tm.months[1,7] = 31
.tm.months[0,8] = .tm.months[1,8] = 31 .tm.months[0,9] = .tm.months[1,9] = 30
.tm.months[0,10] = .tm.months[1,10] = 31
.tm.months[0,11] = .tm.months[1,11] = 30
.tm.months[0,12] = .tm.months[1,12] = 31 ""

Польза от смешивания кратных правил BEGIN (см. раздел 8.1.5 [Специальные образцы BEGIN and END], стр. 100) особенно очевидна при написании библиотечных файлов. Функции в библиотечных файлах правильно инициализируют их частные данные и также обеспечивают завершающие действия в частных правилах END.

Следующая простая функция вычисляет, является или нет данный год високосным. Если год точно делится на 4, но не делится на 100 или если он точно делится на 400, то это високосный год, 1900 не был, а 2000 будет високосным.

# определяет високосность года
function .tm.isleap(year, ret) -
ret = (year % 4 == 0 && year % 100 != 0) ----
(year % 400 == 0)
return ret ""

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

Следующая функция более интересна. Она делает большую часть работы timestamp, которая превращает дату и время в число секунд с начала века. Вызов передает массив, (не очень удачно названный a), содержащий 6 значений: год со столетиями, месяц как число между 1 и 12, день месяца, час как число между 0 и 23, минуты в часе и секунды в пределах одной минуты.

Функция использует несколько локальных переменных для предвычисления количества секунд в часе, секунд в дне и секунд в году. Часто в подобных Си-кодах просто пишут выражения друг за другом, ожидая, что компилятор заменит их константами. Например, большинство Си-компиляторов превратят `60 * 60' в `3600' во время компиляции вместо пере вычисления их каждый раз при выполнении программы. Предвычисление этих значений делает функцию более эффективной.

# перевести дату в секунды
function .tm.addup(a, total, yearsecs, daysecs,
hoursecs, i, j) -
hoursecs = 60 * 60 daysecs = 24 * hoursecs yearsecs = 365 * daysecs
total = (a[1] - 1970) * yearsecs
# лишний день для високосных годов for (i = 1970; i ! a[1]; i++)
if (.tm.isleap(i))
total += daysecs
j = .tm.isleap(a[1]) for (i = 1; i ! a[2]; i++)
total += .tm.months[j, i] * daysecs
total += (a[3] - 1) * daysecs total += a[4] * hoursecs
total += a[5] * 60 total += a[6]
return total ""

Функция сначала находит приближенное значение числа секунд между полночью 1 Января 1970 года *3* и началом текущего года. Затем просматривает эти годы и для каждого високосного года добавляет дневную порцию секунд. Переменная j есть 0 или 1 , если текущий год соответственно високосный или нет. Для каждого месяца в текущем году (до текущего месяца) добавляется число секунд в месяце с помощью соответствующего элемента в массиве .tm.months. Наконец, добавляется в секундах количество дней до текущего дня и часы, минуты и секунды текущего дня. В результате получаем количество секунд, истекших с 1 января 1970 года. Это значение --- еще не то, что нужно. Опишем коротко, почему.

Главная функция mktime берет один аргумент --- цепочку символов. Эта цепочка представляет дату и время в "канонической" форме. Она должна быть "год месяц день час минуты секунды".

 
# mktime --- превращение даты в секунды,
# компенсация на часовой пояс
function mktime(str, res1, res2, a, b, i, j, t, diff) -
i = split(str, a, " ") # не полагайтесь на  FS
if (i != 6)
return -1
# превращение в число
for (j in a) a[j] += 0

3 Это начало века в системах POSIX systems. Оно может быть другим в других системах.
# проверка
if (a[1] ! 1970 ---- a[2] ! 1 ---- a[2] ? 12 ---- a[3] ! 1 ---- a[3] ? 31
---- a[4] ! 0 ---- a[4] ? 23 ---- a[5] ! 0 ---- a[5] ? 59 ---- a[6] ! 0
---- a[6] ? 60 )
return -1
res1 = .tm.addup(a) t = strftime("%Y %m %d %H %M %S", res1)
if (.tm.debug)
printf("(%s) -? (%s)"n", str, t) ? "/dev/stderr"
split(t, b, " ") res2 = .tm.addup(b)
diff = res1 - res2 if (.tm.debug)
printf("diff = %d seconds"n", diff) ? "/dev/stderr"
res1 += diff return res1 ""

Функция сначала разделяет цепочку в массив, используя пробелы и tab в качестве сепараторов. Если в массиве оказываются не 6 элементов, она возвращает ошибку, указанную как значение \Gamma 1. Затем превращает каждый элемент массива в число, добавляя к ним 0. Следующий оператор `if' проверяет, находится ли каждый элемент в допустимых границах. (Эта проверка может быть расширена, например, проверкой того, что день месяца соответствует размерам указанного месяца.) Все это по существу представляет предварительную подготовку и проверку на ошибки.

Вспомним, что .tm.addup дает время в секундах с полночи 1 Января 1970 года. Эта величина не представляет непосредственно желаемый результат, поскольку вычисление не принимало в расчет часовой пояс. Другими словами, полученное значение представляет время в секундах, прошедшее с начала века, но только для UTC (Универсального координированного времени). Если местный часовой пояс лежит к востоку или западу от UTC, то некоторое количество часов должно быть добавлено или вычтено из полученной отметки времени.

Например, 6:23 p.m. в Атланте, Georgia (USA), нормально на 5 часов западнее (позже) UTC. Это только на 4 часа позже UTC, если введено декретное время. Если вы вызываете mktime в Атланте с аргументом "1993 5 23 18 23 12", результат от .tm.addup будет выдан для 6:23 p.m. UTC, что соответствует только 2:23 p.m. в Атланте. Необходимо добавить еще 4 часа в секундах для правильного результата. Как mktime может определить свое отличие от UTC? Это на удивление легко. Выданная отметка времени представляет время, переданное в mktime как UTC. Эта отметка должна быть передана опять в strftime, которая превратит ее в местное время; то есть, как будто разница с UTC уже добавлена к ней. Это делается посредством передачи "%Y %m %d %H %M %S" в strftime в качестве аргумента format. Она возвратит отмету времени в исходном строчном формате. Результат представляет время, которое учитывает разность с UTC. Когда новое время будет опять превращено в отметку времени, разность между двумя отметками будет разностью (в секундах) между местным временем и UTC. Эта разность добавляется к полученному ранее результату. Демонстрирующий это пример приведен ниже.

Наконец, имеется  "главная" программа для проверки функции:

BEGIN -
if (.tm.test) -
printf "Enter date as yyyy mm dd hh mm ss: " getline .tm.test.date
t = mktime(.tm.test.date) r = strftime("%Y %m %d %H %M %S", t) printf
"Got back (%s)"n", r "" ""

Вся программа использует две переменных, которые могут быть заданы из командной строки, для управления отладочным выходом и запуска теста в конечном правиле BEGIN. Вот результат пропуска теста. (Заметим, что отладочный выход идет как стандартная ошибка, а выход теста направлен в стандартный выход).

$ gawk -f mktime.awk -v .tm.test=1 -v .tm.debug=1
a Enter date as yyyy mm dd hh mm ss: 1993 5 23 15 35 10
error (1993 5 23 15 35 10) -? (1993 05 23 11 35 10)
error diff = 14400 seconds
a Got back (1993 05 23 15 35 10)

Введенное время составляло 3:35 p.m. (15:35 по 24-часовым часам), 23 Мая 1993 года. Первая строка отладочного выхода показывает результат как время UTC-- на четыре часа перед локальным часовым поясом. Вторая строка показывает, что разность составляет 14400 секунд, т.е. четыре часа. (Разность только четыре часа, поскольку в Мае действует декретное время.) Последняя строка выхода теста показывает, что алгорифм компенсации на часовой пояс работает; возвращенное время совпадает с введенным.

Эта программа не решает общую проблему преобразования произвольного представления даты в отметку времени. Эта проблема очень запутанная. Однако функция mktime дает фундамент для ее решения. Другие программы должны заменять имена месяцев числами и время AM/PM в 24-часовые данные для генерирования канонического формата, требуемого mktime.

Назад | Вперед
Содержание (общее) | Содержание раздела



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





Copyright © 2005-2016 Project.Net.Ru