PHP5 / Javascript. Сollaboration with Unix timestamps

В большинстве случаев реализация на серверной стороне связана с манипуляциями массивов дат. И удобнее всего использовать так называемые метки времени Unix (целое число, равное разнице в секундах между заданной датой/временем и началом так называемой Эпохи Unix (1 января 1970 00:00:00)). В PHP5 (PHP4) для этого можно воспользоваться следующими методами:

mktime - возвращает метку времени Unix для заданной даты

time - возвращает текущую метку времени Unix

strtotime - преобразует текстовое представление даты в метку времени Unix

Как правило даты на стороне сервера либо приходящие с клиентской стороны, либо отсылаемые клиентской стороне. И часто на стороне клиента нужно не просто отправлять или принимать эти временные данные, но также умеючи их обрабатывать, конечно все зависит от логики вашего приложения. Javascript также предоставляет методы для работы с такого рода метками времени Unix:

Date.parse

Date.UTC

Date.valueOf()

getTime 

...

javascript. Date compare object

Задачка. Как можно адекватно сравнить две даты? К сожалению объект Date не имеет встроенных методов для решения такого рода задачек. Ниже представлен один из способов такого решения.

// вспомогательный объект для сравнения дат в заданном формате, например так - dd.mm.yyyy, или так - yy.dd.mm
var Dates = {
                format : "",   // формат сравниваемых дат
                formatPattern : /^(dd|mm|yy|yyyy)(\.|\-)(?!\1)(dd|mm|yy|yyyy)\2(?!\1)(?!\3)(dd|mm|yy|yyyy)$/gi,                         formatAssoc :     { 1 : 0, 3 : 1, 4 : 2 },   // порядок соответствия индексов формата

                position :         { year : 0, month : 1, day : 2 },  // порядок сравнения частей дат  (год, месяц, день)
                separator : "",                                                      // разделитель (. или -)
                status :         { less : -1, equal : 0, larger : 1 },   // статусные биты
                compare :     function( date1, date2, format )   // основной метод: сравнение дат по заданному формату                                                    
                            {
                                // получение сравниваемых дат
                                var date1 = date1,
                                date2 = date2;
                               
                                // сохранение заданного формата
                                this.setFormat( format );
                               
                                // сравнение дат с первоначальной проверкой заданного формата на валидность использования.
                                // сравнение идет по изначально определенным индесам заданного формата
                                if ( this.checkFormat() )
                                {
                                    // разделение дат по разделителю формата на части (год, месяц, день)
                                    date1 = date1.split( this.separator );
                                    date2 = date2.split( this.separator );
                                   
                                    // сравнение дат по годам:
                                   
                                    if ( date1[ this.position.year ] > date2[ this.position.year ] )
                                    {
                                        return this.status.larger;
                                    }

                                    if ( date1[ this.position.year ] < date2[ this.position.year ] )
                                    {
                                        return this.status.less;
                                    }

                                    if ( date1[ this.position.year ] = date2[ this.position.year ] )
                                    {

                                        // сравнение дат по месяцам:
                                   
                                        if ( date1[ this.position.month ] > date2[ this.position.month ] )
                                        {
                                            return this.status.larger;
                                        }

                                        if ( date1[ this.position.month ] < date2[ this.position.month ] )
                                        {
                                            return this.status.less;
                                        }

                                        if ( date1[ this.position.month ] = date2[ this.position.month ] )
                                        {

                                            // сравнение дат по дням:
                                       
                                            if ( date1[ this.position.day ] > date2[ this.position.day ] )
                                            {
                                                return this.status.larger;
                                            }

                                            if ( date1[ this.position.day ] < date2[ this.position.day ] )
                                            {
                                                return this.status.less;
                                            }

                                            if ( date1[ this.position.day ] = date2[ this.position.day ] )
                                            {
                                                return this.status.equal;
                                            }

                                        }

                                    }

                                }
                                // при отрицательном результате проверки формата на валидность
                                else
                                {
                                    return false;
                                }
                            },
                setFormat : function( format )    // сохранение формата
                            {
                                this.format = format;
                            },
                checkFormat : function()           // проверка заданного формата на валидность  дольнейшего использования 
                            {
                                // проверка формата по шаблону
                                var checkResult = this.formatPattern.exec( this.format );

                                // положительная проверка
                                if ( checkResult != null )
                                {
                                    // распределение индексов формата по порядку сравнения частей дат  (год, месяц, день)
                                    for ( var index in checkResult )
                                    {
                                        // по годам
                                        if ( checkResult[index] == 'yy' || checkResult[index] == 'yyyy' )
                                        {
                                            this.position.year = this.formatAssoc[index];
                                        }
                                        // по месяцам
                                        if ( checkResult[index] == 'mm' )
                                        {
                                            this.position.month = this.formatAssoc[index];
                                        }
                                        // по дням
                                        if ( checkResult[index] == 'dd' )
                                        {
                                            this.position.day = this.formatAssoc[index];
                                        }
                                    }

                                    // установка разделителя для частей дат
                                    this.separator = checkResult[2];

                                    // сброс ресурса
                                    delete checkResult;

                                   
                                    // сброс внутреннего индекса шаблона проверки
                                    this.formatPattern.lastIndex = 0;

                                    return true;

                                }
                                // отрицательная проверка
                                else
                                {
                                    return false;
                                }

                            }
            };


Обратите на одну особенность в проверке формата по шаблону в методе checkFormat : 


var checkResult = this.formatPattern.exec( this.format );

Каждый второй вызов данного метода будет приводить к неоднозначности и связано это будет со спецификой поиска совпадений: будет возвращаться null. Этого в нашем случае не требуется, чтобы этого избежать введен сброс внутреннего индекса шаблона проверки ():
  
this.formatPattern.lastIndex = 0;

Желаю Всем удачи в нашем нелегком деле :)

PHP5. Особые случаи в условных и циклических выражениях

Громко конечно сказано - особые случаи. Просто иногда приходиться сталкиваться с определенными конструкциями, в которых можно допустить ошибку.

1 случай. Неоднозначность результата использования составных предикатов в условиях

Для наглядности - пример. Пусть даны первоначальные параметры:

$flag = false;
$n = 1;


А также дано такого рода условие:

if ( $flag && $n++ )
{
    // some code
}


Что мы получим на выходе? Вроде бы $n за счет посткрементной формы должен увеличиться на 1, то есть должны получить число - 2, но этого не произойдет, даже если воспользуемся прекрементной формой (++$n).
Так как параметр $flag равен false, то интерпретатор далее условие не просматривает, он "знает", что если один из предикатов установлен в false, то конечный результат логического сравнения также даст false. Помните правило конъюнкции ( логическое умножение ) из булевой алгебры! :) Поэтому далее вычисление не происходит.

Похожая ситуация возникает и в следующем условии:

if ( $flag || $n++ )
{
    // some code
}


Если $flag установлен в false, то все хорошо - далее проходит вычисление, но если $flag будет установлен в true, тогда вычисление не произойдет. Снова имеем дело с булевой алгебры - правило дизъюнкции ( логическое сложение ): в данном случае если один из предикатов установлен в true, то независимо от состояния ( true или false ), результатом логического сравнения будет true. В этом причина отсутствия вычисления.

Такого рода проявления вызваны оптимизацией работы интерпретатора с условными выражениями: быстро посмотрел, оценил и принял соответствующее решение. Логично, не так ли?!

Также стоит отметить, что интерпретатор просматривает условия слева направо, то есть если в приведенных примерах предикаты поменять местами, то такие исключения будут устранены.

Для заметки можно также подметить, что такого рода условные проверки встречаются во многих языках и даже в SQL.  

2 случай. Неоднозначность результата в циклах

Рассмотрим простой цикл.

for ( $i = 0; $i < 5; $i++ )
{
    if ( $i == 3 )
        continue;
       
    print( $i.'</br>' );       
}


Данный цикл отрабатывая выдает последовательность чисел: 0 1 2 4, 3 из этой последовательности выпадает: на этом шаге условие становится истинным, срабатывает инструкция continue; которая вынуждает цикл перейти к следующей итерации. Ну тут все понятно. Но что будет, если в иструкции continue; мы случайно
не проставим завершающее любое выражение точку с запятой, то есть:

for ( $i = 0; $i < 5; $i++ )
{
    if ( $i == 3 )
        continue
       
    print( $i.'</br>' );       
} 


По идее, интерпретатор в этом случае должен выбросить исключение, но что же происходит на самом деле.
Если запустить данный цикл, то на выходе получим следующее: 3. Неожиданно, покрайней мере для меня это было неожиданно. Такой же результат можно получить и в следующем цикле:

for ( $i = 0; $i < 5; $i++ )
{
    if ( $i == 3 )
        break
       
    print( $i.'</br>' );       
}


С чем это может быть связано? Происходят такие чудеса по двум причинам: 1 - у блока условия явно не определена область действия, а инструкции continue и break в свою очередь пытаются отыскать завершающие ; и в это же время на пути
встречается инструкция print( $i.'</br>' ), которая выводит соответствующее число, и далее выражение завершается на искомом завершающем символе. Что в итоге получается? Получается, что интерпретатор расширил область действия
данного условия, поэтому только число 3 и выводится. Таким образом интерпретатор был введен в замешательство, такого не произошло бы, если мы имели дело с компилятором, например в C++.

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

for ( $i = 0; $i < 5; $i++ )
{
    if ( $i == 3 )
    {
        continue
    }
       
    print( $i.'</br>' );       
}


Если же теперь попытаться повторить приведенные выше "чудеса" - ничего не выйдет, интерпретатор укажет вам на наличие
ошибки. Но если внутри этого блока также проставить команду с завершающим ; все снова отработает как ни в чем не бывало. М-да.

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

Oracle SQL Developer. ORA-12705: Cannot access NLS data files or invalid environment specified. Resolve

Столкнулся с проблемой подключения Oracle SQL Developer к СУБД Oracle 11g XE. При попытке создать соединение к стандартному для  Oracle 11g XE экземпляру БД (SID) - XE получаю ошибку - ORA-12705: Cannot access NLS data files or invalid environment specified. И это не смотря на то, что подключение через SQL Plus проходит успешно. Проверил запись в tnsnames.ora. Вроде все хорошо.


Но все же проблема была найдена. Все дело в локали. Для устранения данной ошибки нужно в настройках SQL Developer - \sqldeveloper\ide\bin\ - в файлик - ide.conf - добавить следующие строчки:

AddVMOption -Duser.region=us
AddVMOption -Duser.language=en


Рестартуйте Ваш SQL Developer, если он был запущен, и вуаля - все готово. Ниже приведен скриншот успешного тест-коннекта. Всем успехов.


Oracle 11g XE. Install SCOTT/TIGER scheme

Для тестирования СУБД Oracle очень удобно пользоваться стандартной схемой SCOTT/TIGER. Но в последнем релизе, доступном для общедоступного пользования - Oracle Database Express Edition 11g Release 2 она отсутствует. Как быть? Можно конечно самому спроектировать некую базу данных, создать пользователя, наделить его правами и в путь дорожку. Но часто на глаза попадают мануалы, где рассматриваются возможности СУБД именно с использованием старого доброго малого - SCOTT/TIGER. Для выполнения последующих шагов воспользуемся утилитой - SQL Plus.

CONNECT SYS/пароль AS SYSDBA;

CREATE USER SCOTT
IDENTIFIED BY TIGER

DEFAULT TABLESPACE USERS
TEMPORARY TABLESPACE TEMP;

GRANT CONNECT TO SCOTT;

GRANT RESOURCE TO SCOTT;

ALTER USER SCOTT DEFAULT ROLE CONNECT, RESOURCE;

GRANT UNLIMITED TABLESPACE TO SCOTT;


Далее нужно выполнить sql-скрипт (проверьте правильность Вашего пути):

@C:\oraclexe\app\oracle\product\10.2.0\server\RDBMS\ADMIN\scott.sql


Ну вот и все, все готово :)