Главная страница Visual 2000 · Средства разработки · Общий список статей · Общий список статей по VB/VBA

Visual Basic и проблема 2000 года

Андрей Колесов

© 1999, Андрей Колесов
Авторский вариант. Статья была опубликована c незначительной литературной правкой в журнале "КомпьютерПресс" № 7/99 и размещена на прилагаемой к нему компакт-диске в виде файла VB2000.htm. Обратите внимание, что файл, с которым вы работаете сейчас, не является копией VB2000.htm ни по содержанию, ни по дизайну.

В какой степени Visual Basic
Преобразование из двухзначного в четырехзначное представление
Очевидное и простое решение
Срок работоспособности программ
Работа с датами
Национальные особенности
Возможные проблемы


В какой степени Visual Basic

В какой степени Visual Basic соответствует требованиям 2000 года? Ответ Microsoft такой:

1) 32-разрядные версии (4.0 — 6.0) — соответствуют с незначительными проблемами;

2) 16-разрядные версии (1.0 — 4.0) — не соответствуют;

3) версии для DOS (QB 4.5, PDS 7.1) — не будут тестироваться.

Мое мнение несколько иное: Microsoft сильное преувеличивает опасность проблем в VB. На мой взгляд их просто нет во всех перечисленных версиях, но нужно знать особенности разных версий и соблюдать определенные правила при написании программного кода.

В начало статьи

Преобразование из двухзначного в четырехзначное представление

Главное проблемой (по мнению Microsoft) является различия правилах преобразования года из двухзначного в четырехзначное представление. Впрочем, эти правила она сама же и меняет — четыре раза за последние пять лет.

Все версии Visual Basic for Windows до версии 3.0 включительно (а также более ранние DOS-овские варианты: VB 1.0 for DOS, QB 4.5 и PDS 7.1) двузначное представление года всегда преобразовывали в четырехзначное простым добавлением 1900. Программы такого преобразования встроены в состав внутренних библиотек продуктов и поэтому не зависят от версии операционной системы и значения текущей даты.

Отмечу от себя, что в версиях QB и PDS проблема преобразования года вообще никогда не была актуальной. Ведь единственным оператором языка, где использовалось это правило, в то время был только DATE$ — программная запись системной даты в MS-DOS. Такая функция в обычных приложениях практически не применялась. Для обычной работы с датами нужно было писать собственные процедуры, и их качество уже зависело от программиста (об этом будет разговор дальше).

В период создания VB 4.0 появился первый вариант VBA (в составе Excel 4.0) и механизм OLE Automation. В этой связи основные функции преобразования дат были переданы библиотекам OLE Automation (а не внутренним библиотекам пакетов), которым пользовались VB 4.0 и VBA. Исключением была только функция DateSerial, которая осталась внутри самого VB 4.0. (для ее реализации возможностей библиотек OLE Automation в те времена не хватало). Тогда же было изменено правило преобразования года: для двухзначного формата использовалось значение текущей системной даты. То есть сегодня при работе в VB 4.0 (16 бит) 99 сегодня будет означать 1999, а через год — 2099.

Первоначальный 32-разрядный вариант VB 4.0 использовал тот же алгоритм, что и 16-разрядный. В нем использовалась 32-разрядная Automation библиотека OleAut32.dll версии 2.10, которая входила в состав пакета. Однако позднее Microsoft решила изменить правило, введя окно в диапазоне 1930-2029 гг.: года 0-29 стали относиться к 21 веку, 30-99 — к 20-му. Однако такое изменения было выполнено только для 32-разрядного варианта OleAut32.dll (начиная с версии 2.20.4049). Таким образом VB 4.0 с новой библиотекой стал обрабатывать двухзначное представление года по новым правилам, кроме (ВНИМАНИЕ!) встроенной функции DateSerial, которая по-прежнему ориентировалась на текущее значение системной даты.

В VB и VBA (Office 97) 5.0 функция DateSerial работает уже по новым правилам (1930-2029), так как здесь используется не внутренняя библиотека пакета, а единая OleAut32.dll. Эта версия библиотеки входит в состав многих продуктов (не только Microsoft), выпущенных в 1996 году и позднее.

В сентябре прошлого года Microsoft выпустила VB 6.0, в котором был реализован тот же механизм преобразования года, что и в VB 5.0. Но не расслабляйтесь: это относится только к первым рабочим вариантам (в частности, как сообщает Microsoft, с датой до 1 августа 1998 года). В состав уже осенних релизов VB 6.0 будет включена новая версия библиотек OLE Automation, где алгоритм вычисления года опять изменен.

Но эта информация, приведенная на Web-узле Microsoft по состоянию на 6 марта 1999 года, не очень точна. Лично у меня установлен коробочный VB 6.0, приобретенный в октябре 1998 года с номером версии 6.00.8176 и датой 25.06.98. В его состав входит OleAut32.dll версии 2.30.4261 с той же датой и она уже работает по новым правилам: диапазон 100-летнего промежутка определяется установками в диалоговом окне "Control Panel|Regional Settings|Date" в Windows 98 (рис. 1 — установлен диапазон 1937-2036). Так же работает стандартная библиотека, входящая в состав Windows 98. Новая библиотека OleAut32.dll входит в состав многих новых продуктов, но для Windows 95 она может использовать диапазон, установленный по умолчанию — 1930-2029.

Обновление OleAut32.dll соответственно изменяет работу с датами в VB 4.0 и VB/VBA 5.0.

В начало статьи

Очевидное и простое решение

Вы еще успеваете следить за изменениями алгоритма преобразования даты? Короче говоря, чтобы определить, каким образом VB-приложение делает из двухзначного года его четырехзначное представление нужно знать версию VB (для 4.0 еще и разрядность — 16 или 32), версию библиотеки OleAut32.dll и версию Windows (нужно знать еще и региональные установки, но об этом поговорим позднее). Убедиться, как же работает это преобразование на вашем компьютере, можно с помощью одной строчки кода:

Debug.Print Year(Выражение с датой)

Решение проблемы очевидно — нужно сделать собственную простую подпрограмму преобразования формата даты и не зависеть ни прихотей Microsoft. Для примера создайте форму, на которой разместите окно ввода Text1, метку Label1 и командную кнопку Command1 (рис. 2). Напишите программный код для процедур Command1_Click и ConvertYear (листинг 1). Запустите приложение. Далее вводите исходную дату в текстовом окне и после щелчка кнопки вы увидите в поле метки преобразованный вариант (в данном случае в диапазоне 1951-2050 гг.)

Процедуру ConverYear можно разместить в BAS-модуле или даже в классе (поместив потом в OLE-сервер) и использовать в любом месте вашего приложения. Переменную YearWindow% можно объявить глобальной или передавать в качестве параметра и менять ее значение динамически в процессе работы приложения.

В начало статьи

Срок работоспособности программ

В материалах Microsoft указано, что срок работоспособности VB (включая последнюю версию 6.0) — до 2030 года, а не до 2035 года, как это записано в требованиях 2000 корпорации (см. "Проблема Y2K и продукты Microsoft"). Именно поэтому VB 5.0 и 6.0 причислены к категории "соответствуют с незначительными проблемами". В чем причина таких временных границ, мне выяснить не удалось (даже после обращения с этим вопросом в Microsoft). Однако работа в тестовом режиме с QB 4.5 и VB 3.0-6.0 в течение недели с датой "март 2079 года" не выявила никаких проблем.

В начало статьи

Работа с датами

Начиная с первой версии, в VB была введен понятие типа данных для хранения даты и тогда же появились специальные операции для работы с ними. Однако до версии 3.0 для этого просто использовался тип Variant (подтип 7) и только, начиная с 4.0, был введен специальный тип Date.

Переменная типа Date физически представляет собой вещественное число двойной точности (восемь байтов) формата IEEE, в котором хранится дата для диапазона от 1 января 100 года до 31 декабря 9999 года и время от 0:00:00 до 23:59:59. Сама дата равна целой части этого числа и соответствует порядковому номеру суток, начиная от 30 декабря 1899 года. (0 — это 30.12.1899, значения до и после этой даты имеют соответственно отрицательное и положительное значение.) Времени соответствует дробная часть числа: полночь — 0,0, а полдень — 0,5.

Если вы запустите на выполнение код (для российских региональных установок):

Dim D1 As Double, D2 As Date
D2 = "2 апреля 1999 15:51:56"
D1 = D2
Print D1; D2
D2 = Clng(D2) + 100
Print D2
D2 = 100
Print D2

то получите такой результат:

36252.6610648148  02.04.99 15:51:56
12.07.99
09.04.1900

ПРИМЕЧАНИЕ. Возможность использования алгоритма, применяемого Microsoft для расчета дат и дней недели, до 15 октября 1582 года вызывает серьезные возражения. Подробнее — см. статью "Y2K: как вести календарь?"

Для определения даты можно использовать любые символьные или числовые выражения, а также литералы (выражения заключенный в скобки #), которые могут быть интерпретированы как корректное обозначение даты, например:

"2 апреля 1999", #1 Jan 93#, "02.04.99", 100

Но надо иметь в виду, что попытка присвоения некорректного значения даты вызывает ошибку и останов программы. Поэтому при вводе даты пользователем, перед присвоением ее значения переменной следует проверить ее на правильность с помощью функции IsDate (см. листинг 1).

Для работы с датами в VB имеется целый ряд специальный функций. Версия 5.0 включает такой набор: Now, CDate, CVDate, DateValue, Date, Date$, Format, DateAdd, DateDiff, DatePart, IsDate, Day, Month, Weekday, Year. В VB6 добавлены еще несколько дополнительных функций, которые позволяют преобразовывать дату и отдельные ее элементы в строковое выражение: MonthName, WeekdayName, FormatDateTime. (Следует иметь в виду, что по умолчанию отсчет дней недели в VB ведется, начиная с воскресенья.)

В начало статьи

Национальные особенности

При работе с датой нужно учитывать влияние региональных установок. Проблема заключается в том, что при использовании национальных параметров (в нашем случае российских) VB в одних случаях использует эти установки, в других — исходные, американские. Поэтому не стоит удивляться, что некоторые примеры, приведенные в справочной системе будут работать на вашем компьютере не так, как это сказано в их описании.

Мы рассмотрим здесь только несколько примеров, которые должны показать, то при работе с датами нужно внимательно изучить их специфику и, в частности, учесть возможное влияние изменения региональных установок на работу программы. Сейчас разговор будет идти на примере, международной Windows 98 в российскими параметрами.

Вывод даты всегда выполняется в формате, определенным в региональных установках (для России — ДД.ММ.ГГ), но с их вводом есть проблемы. Для примера введите:

Dim D As Date
D = "2 апреля 1999": Print D
D = "2.04.99": Print D
D = "2/04/99": Print D
D = "2 Apr 99": Print D

В первых трех случаях будет напечатано одно и тоже — 02.04.99. А в четвертом будет ошибка программы — английское строковое выражение является недействительным. В варианте США первые два выражения будут ошибочными, а двух последних будут выдано — 02/04/99 (2 февраля!) и 04/02/99 (2 апреля).

Еще больше неожиданностей ждет тех, кто предпочитает иметь дело с литералами. Дело в том, что VB при работе с ними использует только встроенный американский вариант, игнорируя региональные установки. Попытка ввести D = #2 апреля 1999# или D = #2.04.99# сразу же вызовет сообщение об ошибке. В то же время при работе с российскими (!) установками строки

D = #04/02/99# или D = #2 Apr 99#

cразу будут преобразованы в

D = #4/2/99#

что будет соответствовать 2 апреля (а не 4 февраля). Для примера выполните такой код:

D1 = #2/4/99#: D2 = "02/04/99"
Print D1, D2

В русском варианте будет напечатано:

04.02.99  02.04.99   ' 4 февраля и 2 апреля

В американском варианте будет напечатано:

02/04/99  02/04/99   ' 4 февраля и 4 февраля

Еще один вопрос: использование значения текущей даты, которое определяется с помощью функций Date и Date$. Первая возвращает значение даты в числовом виде, вторая — в символьном, который имеет формат "MM-DD-YYYY" независимо от региональных установок. Выполните такой код (для текущей даты 2 апреля):

D1 = Date
D2 = Date$
Print D1; D2; Date$

В русском варианте будет напечатано:

02.04.99  04.02.99  04-02-1999

В американском варианте будет напечатано:

04/02/99  04/02/99  04-02-1999

В начало статьи

Возможные проблемы

Ключевая проблема заключается в том, что работы с датами часто приходится использовать, кроме специального типа данных Date, еще и символьный формат строковых переменные. Тип String обычно используется для ввода данных, и часто применяется в пользовательских процедурах для какой-то специальной обработки. Строковый формат наверняка понадобится, если вы захотите работать с датами юлианского календаря (см. "Y2K: как вести календарь?"). Типичной проблемы является аварийное завершение программы в момент преобразования даты (неверного формата) из символьного представления в тип Date.

С учетом всего сказанного сформулируем следующие СОВЕТЫ:

В начало статьи