parser

Написать ответ на текущее сообщение

 

 
   команды управления поиском

Меняю код на Parser на регулярное выражение... ;)

serglif 23.11.2004 13:51

Написал класс для работы с датами расширенного диапазона. Если кому нужно - пользуйтесь на здоровье. Буду очень рад замечаниям. Но по хорошему в конструктор нужно вставить регулярное выражение, проверяющее правильность ввода даты и разбивающее дату на годы, дни, часы и т.д. Изучать RCPE пока некогда... если у кого есть, может поделитесь? Варианты строки с датой как в date::create[]. Код класса:
#==========================================================================================
# Класс для работы с датами расширенного диапазона. (v1.0) Автор: С. Лифшиц (serlif@mail.ru)
#==========================================================================================
#
# Метод print и массивы локальных названий месяцев взяты из класса dtf.p
# (http://www.parser.ru/examples/date/) Михаила Петрушина (http://misha.design.ru/).
# Алгоритмы работы с модифицированными юлианскими датами взяты на http://alglib.manual.ru/
#
#                    Диапазон класса: 17.11.1858 - 23.12.54078.
#
# Верхний предел занижен, так как за ним начинаются ошибки в вычислениях (связанные
# видимо с переполнением int). Некогда разбираться... Дальше наверное нужно только астрономам. :)
#
# Класс в первую очередь быд предназначен для обработки дат, хранящихся
# в СУБД и выходящих за стандартный диапазон. Поэтому я обошелся без регулярного выражения
# в конструкторе.
#
# Поля класса аналогичны Parser-овскому (www.parser.ru/docs/lang/datefields.htm):
# day, month, year, hour, minute, second, weekday, yearday, daylightsaving
#
# Дополнительные поля: millisecond - миллисекунды, julian - дата в модифицированном
# юлианском формате (количество дней, прошедших с 17.11.1858), russian - дата по русски
# в виде "ДД Месяц ГГГГ, ДеньНедели", timestamp- количество секунд, прошедших с начала
# текущих суток
#
# Примечание: Поскольку зимнее и летнее время в любом случае порождает
# неопределенности (попробуйте сказать какое время 2004-10-31 02:00:01),
# то поле daylightsaving вычисляется и для параметра без времени, говоря
# в этом случае какое в этот день используется время (здесь неопределенности для
# последнего воскресения марта и октября)
#
# Методы:
#
# @create[sql-date] - конструктор
#
# @roll[target;offset] - сдвигает дату на заданное количество единиц (в target: year, month, day)
#
# @print[sql-date;format;locale] - вывод даты, используя форматную строку и локальные названия месяцев
#
# @dayofweek[year;month;day] - определение дня недели для введенной даты
#
# @daysbetween[year1;month1;day1;year2;month2;day2] - вычисление количества дней между датами
#
# @getjulian[year;month;day] - переводит дату в модифицированную юлианскую
#
# @fromjulian[julian] - переводит дату из модифицированной юлианской в обычную
#
#==========================================================================================

@CLASS
cdate

#==========================================================================================
# Конструктор класса
#==========================================================================================
@create[sql-date][date;cdate][tmp]

 $count[^sql-date.split[ ]]
 $date[^sql-date.split[ ;h]]
 
# Заполняем поля, относящиеся к дате
 $cdate[^date.0.split[-;h]]
 $year($cdate.0) $month($cdate.1) $day($cdate.2)
 $hour(0) $minute(0) $second(0) $millisecond(0)

# Переводим дату в юлианскую
 $julian(^getjulian[$year;$month;$day])
 
# Если вышли за диапазон класса - выдаем ошибку
 ^if($julian<0 || $julian>19073000){
  ^throw[bad.command;cdate:create;date '${year}-${month}-${day}' is out of valid range]
 }

# Корректируем значения для ошибочных дат (ex. 2000-02-31)
 $tmp[^fromjulian[$julian]]
 $year($tmp.year) $month($tmp.month) $day($tmp.day)

# Если в параметре есть время - заполняем поля
 ^if(^count.count[]>1){
 
  $time[^date.1.split[.;h]]
  $count[^date.1.split[.]]
  $ctime[^time.0.split[:;h]]

  $timestamp(^ctime.2.int(0)+^ctime.1.int(0)*60+^ctime.0.int(0)*3600)
  ^if(^count.count[]>1){
   $timestamp($timestamp+^time.1.int(0)\1000+(^time.1.int(0)%1000)/1000)
  }
  
# Корректируем значения для ошибочного времени (ex. 26:69:84 = Сутки + 3:10:24)
  $julian($julian+$timestamp\86400)
  $timestamp($timestamp%86400)
  $tmp[^fromjulian[$julian]]
  $year($tmp.year) $month($tmp.month) $day($tmp.day)

# Заполняем время
  $hour($timestamp\3600)
  $minute(($timestamp%3600)\60)
  $second(^math:trunc(($timestamp%3600)%60))
  ^if(^count.count[]>1){$millisecond(^math:frac($timestamp)*1000)}
 }

 ^advancedfields[]
 
#==========================================================================================
# Вычисляет расширенные поля: день недели, день года и т.д.
#==========================================================================================
@advancedfields[][marth;october]

 $weekday[^dayofweek[$year;$month;$day]]
 $yearday[^daysbetween[$year;1;1;$year;$month;$day]]

# Вычисляем принадлежит ли день периоду летнего времени
 $marth(32-^dayofweek[$year;03;25])
 $marth[^daysbetween[$year;1;1;$year;3;$marth]]
 $october(32-^dayofweek[$year;10;25])
 $october[^daysbetween[$year;1;1;$year;10;$october]]
 $daylightsaving(^if($yearday>=$marth && $yearday<=$october){1}{0})

# Уточнение для летнего и зимнего времени
 ^if($yearday==$marth && $hour==2){^hour.dec[]}
 ^if($daylightsaving && def $time){
  ^if($yearday==$marth && $hour<2){$daylightsaving(0)}
  ^if($yearday==$october && $hour>=2){$daylightsaving(0)}
 }

 ^leapyear[]
 $russian[^print[;%e %h %Y, %A]]

#==========================================================================================
# Сдвигает дату на заданное количество единиц
#==========================================================================================
@roll[target;offset][tmp]

# Годы
 ^if($target eq year){
  $year($year+^offset.int(0))
 }
 
# Месяцы
 ^if($target eq month){
  $month($month+^offset.int(0)%12)
  $year($year+^offset.int(0)\12)
  ^if($month<=0){
   $month(12+$month)
   ^year.dec[]
  }
  ^if($month>12){
   $month($month-12)
   ^year.inc[]
  }
 }
 
# Дни
 ^if($target eq day){
  $julian($julian+^offset.int(0))
  $tmp[^fromjulian[$julian]]
  $year($tmp.year) $month($tmp.month) $day($tmp.day)
 }

# Перевычисляем доп. поля для обновленной даты
 ^leapyear[]
 ^if($day>$dayinmonth.$month){$day($dayinmonth.$month)}
 
 $julian[^getjulian[$year;$month;$day]]
 
# Если вышли за диапазон класса - выдаем ошибку
 ^if($julian<0 || $julian>19073000){
  ^throw[rolled.out;cdate:roll;bad resulting date '${year}-${month}-${day}'(rolled out of valid date range)]
 }
 
 ^advancedfields[]

#==========================================================================================
# Коррекция количества дней в феврале для високосных лет
#==========================================================================================
@leapyear[]

 ^if($year%4==0 && ($year%100!=0 || $year%400==0)){$dayinmonth.2[29]}{$dayinmonth.2[28]}

#==========================================================================================
# Вычисляет день недели
#==========================================================================================
@dayofweek[y;m;d][jul]

 $jul(^getjulian[$y;$m;$d])
 $result(($jul%7+3)%7)

#==========================================================================================
# Вычисляет количество дней между датами
#==========================================================================================
@daysbetween[y1;m1;d1;y2;m2;d2][date1;date2]

 $result(^getjulian[$y2;$m2;$d2]-^getjulian[$y1;$m1;$d1])

#==========================================================================================
# Переводит дату в модифицированную юлианскую
#==========================================================================================
@getjulian[y;m;d][a;b]

 $y(^y.int(0)) $m(^m.int(0)) $d(^d.int(0))
 $a(10000*$y+100*$m+$d)
 ^if($m<=2){^m.inc(12) ^y.dec(1)}
 ^if($a<=15821004){
  $b(-2+($y+4716)\4-1179)
 }{
  $b($y\400-$y\100+$y\4)
 }
 $a(365*$y-679004)
 $result($a+$b+306001*($m+1)\10000+$d)

#==========================================================================================
# Переводит дату из модифицированной юлианской в обычную
#==========================================================================================

@fromjulian[mjd][jd;b;c;d;e;f;da;mo;ye]

 $jd($mjd+2400001)
 
 ^if($jd<2299161){
  $b(0)
  $c($jd+1524)
 }{
  $b(($jd*100-186721625)\3652425)
  $c($jd+($b-$b\4)+1525)
 }
 
 $d((100*$c-12210)\36525)
 $e(365*$d+$d\4)
 $f(($c-$e)*10000\306001)
 $da(^math:trunc($c-$e+0.5)-^math:trunc($f*30.6001))
 $mo($f-1-12*($f\14))
 $ye($d-4715-(7+$mo)\10)

 $result[$.day($da) $.month($mo) $.year($ye)]

#==========================================================================================
# Вывод даты, используя форматную строку.
# Формат строки понятен из вариантов switch
#==========================================================================================

@print[sql-date;format;locale][tmp;temp;year;month;day;hour;minute;second]

# Если дата не задана - печатаем для текущего объекта
 ^if(!def ${sql-date}){
  $year($self.year) $month($self.month) $day($self.day) $hour($self.hour)
  $minute($self.minute) $second($self.second) $millisecond($self.millisecond)
 }{
  $temp[^cdate::create[$sql-date]]
  $year($temp.year) $month($temp.month) $day($temp.day) $hour($temp.hour)
  $minute($temp.minute) $second($temp.second) $millisecond($temp.millisecond)
 }
 
 ^if(!def $locale){$locale[$rr-locale]}

 $result[
  ^format.match[%(.)][g]{
   ^switch[$match.1]{
  
    ^case[%]{%}

    ^case[e]{$day}
    ^case[d]{^day.format[%02d]}

    ^case[c]{$month}
    ^case[m]{^month.format[%02d]}
    ^case[h]{$locale.month.[$month]}

    ^case[Y]{$year}
    ^case[y]{$tmp($year % 100)^tmp.format[%02d]}

    ^case[w]{$weekday}
    ^case[a;A]{$locale.weekday.[$weekday]}

    ^case[D]{^month.format[%02d]/^day.format[%02d]/$year}

    ^case[H]{^hour.format[%02d]}
    ^case[M]{^minute.format[%02d]}
    ^case[i]{^minute.format[%02d]}
    ^case[S]{^second.format[%02d]}

    ^case[T]{^hour.format[%02d]:^minute.format[%02d]:^second.format[%02d]}
   }
  }
 ]
 
#==========================================================================================
# Вспомогательные переменные
#==========================================================================================
@auto[]

$dayinmonth[
            $.1[31] $.2[28] $.3[31] $.4[30] $.5[31] $.6[30]
            $.7[31] $.8[31] $.9[30] $.10[31] $.11[30] $.12[31]
           ]

$rr-locale[
	$.month[
		$.1[Января]
		$.2[Февраля]
		$.3[Марта]
		$.4[Апреля]
		$.5[Мая]
		$.6[Июня]
		$.7[Июля]
		$.8[Августа]
		$.9[Сентября]
		$.10[Октября]
		$.11[Ноября]
		$.12[Декабря]
	]
	$.weekday[
		$.0[Воскресенье]
		$.1[Понедельник]
		$.2[Вторник]
		$.3[Среда]
		$.4[Четверг]
		$.5[Пятница]
		$.6[Суббота]
		$.7[Воскресенье]
	]
]
$ri-locale[
	$.month[
		$.1[Январь]
		$.2[Февраль]
		$.3[Март]
		$.4[Апрель]
		$.5[Май]
		$.6[Июнь]
		$.7[Июль]
		$.8[Август]
		$.9[Сентябрь]
		$.10[Октябрь]
		$.11[Ноябрь]
		$.12[Декабрь]
	]
	$.weekday[
		$.0[Воскресенье]
		$.1[Понедельник]
		$.2[Вторник]
		$.3[Среда]
		$.4[Четверг]
		$.5[Пятница]
		$.6[Суббота]
		$.7[Воскресенье]
	]
]
$rs-locale[
	$.month[
		$.1[Янв]
		$.2[Фев]
		$.3[Мар]
		$.4[Апр]
		$.5[Май]
		$.6[Июн]
		$.7[Июл]
		$.8[Авг]
		$.9[Сен]
		$.10[Окт]
		$.11[Ноя]
		$.12[Дек]
	]
	$.weekday[
		$.0[Вс]
		$.1[Пн]
		$.2[Вт]
		$.3[Ср]
		$.4[Чт]
		$.5[Пт]
		$.6[Сб]
		$.7[Вс]
	]
]
# английская locale
$es-locale[
	$.month[
		$.1[Jan]
		$.2[Feb]
		$.3[Mar]
		$.4[Apr]
		$.5[May]
		$.6[Jun]
		$.7[Jul]
		$.8[Aug]
		$.9[Sep]
		$.10[Oct]
		$.11[Nov]
		$.12[Dec]
	]
	$.weekday[
		$.0[Sun]
		$.1[Mon]
		$.2[Tue]
		$.3[Wed]
		$.4[Thu]
		$.5[Fri]
		$.6[Sat]
		$.7[Sun]
	]
]
$ei-locale[
	$.month[
		$.1[January]
		$.2[Febrary]
		$.3[March]
		$.4[April]
		$.5[May]
		$.6[June]
		$.7[July]
		$.8[August]
		$.9[September]
		$.10[October]
		$.11[November]
		$.12[December]
	]
	$.weekday[
		$.0[Sunday]
		$.1[Monday]
		$.2[Tuesday]
		$.3[Wednsday]
		$.4[Thusday]
		$.5[Friday]
		$.6[Satarday]
		$.7[Sunday]
	]
]
# украинская locale
$us-locale[
	$.month[
		$.1[Сiч]
		$.2[Лют]
		$.3[Бер]
		$.4[Квi]
		$.5[Тра]
		$.6[Чер]
		$.7[Лип]
		$.8[Сер]
		$.9[Вер]
		$.10[Жов]
		$.11[Лис]
		$.12[Гру]
	]
	$.weekday[
		$.0[Нед]
		$.1[Пон]
		$.2[Вiв]
		$.3[Сер]
		$.4[Чет]
		$.5[П'я]
		$.6[Суб]
		$.7[Нед]
	]
]
$ui-locale[
	$.month[
		$.1[Сiчень]
		$.2[Лютий]
		$.3[Березень]
		$.4[Квiтень]
		$.5[Травень]
		$.6[Червень]
		$.7[Липень]
		$.8[Серпень]
		$.9[Вересень]
		$.10[Жовтень]
		$.11[Листопад]
		$.12[Грудень]
	]
	$.weekday[
		$.0[Недiля]
		$.1[Понедiлок]
		$.2[Вiвторок]
		$.3[Середа]
		$.4[Четвер]
		$.5[П'ятниця]
		$.6[Субота]
		$.7[Недiля]
	]
]