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


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

PHP5. Ссылки на объекты. Внешние и внутренние

В PHP5 все переменные - это ссылки на содержимое переменной. Для получения доступа к содержимому переменной используются ссылками. Важно помнить, что эти ссылки не есть указатели как в C/C++, которые содержат адреса на ячейки памяти, они лишь ссылаются на некоторое содержимое. Так же дело обстоит и с ссылками в python`е. Но сейчас не об этом. В PHP5 ссылка по-сути своей определяет жизнь переменной, точнее того, куда она ссылается: при удалении переменной ее содержимое может не сразу удалиться. С чем это может быть связано? За такую очистку как мы знаем отвечает сборщик мусора (garbage collector). А он смотрит как раз на то, есть ли ссылки на данные или нет, если нет, то все будет почищено, а иначе зачистка будет пропущена. Продемонстрирую на примере.

class Node
{
    var $str; // внутренние данные
    var $ref; // внетренняя ссылка
  
    // получение внутренних данных
    function getStr()
    {
        return $this->str;
    }
  
    // установить внутренние данные
    function setStr( $str )
    {
        $this->str = $str;
    }
  
    // получить внешнюю ссылку
    function getNext()
    {
        return $this->ref;
    }
  
    // установить внешнюю ссылку
    function setNext( &$ref )
    {
        $this->ref = $ref;
    }
  
    function __construct()
    {
        echo 'constructor<br/>';
    }
  
    function __destruct()
    {
        echo 'destructor -> '.$this -> getStr().'<br/>';
    }
  
}

// Создаем первый объект. Переменная получает ссылку на данный объект
$first = new Node;
// Создаем второй объект. Переменная получает ссылку на данный объект
$second = new Node;

// Помещаем данные в первый объект
$first->setStr( '$first' );
// Помещаем данные во второй объект
$second->setStr( '$second' );

// Привязываем первый объект ко второму за счет ссылки внутреннего члена $ref на второй объект
$first->setNext( $second );
// Привязываем второй объект к первому за счет ссылки внутреннего члена $ref на первый объект
$second->setNext( $first );

// Удаляем переменную $first, тем самым мы уничтожаем ее ссылку на объект
unset( $first );
// Удаляем переменную $second, тем самым мы уничтожаем ее ссылку на объект
unset( $second );

echo 'Debug<br/>';


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

constructor
constructor
Debug
destructor -> $first
destructor -> $second


Вроде бы ничего особенного, но присмотритесь на месторасположение слова Debug. Ведь мы уничтожили все переменные до момента вывода этого слова командами unset( $first ) и unset( $second ). То есть должны были сработать деструкторы наших объектов. Но на деле видим, что это не так. В чем дело? На самом деле мы создали перекрестные ссылки между первым и вторым объектами. Эти ссылки внутренние, и поэтому когда мы уничтожили наши переменные, мы уничтожили лишь внешние ссылки на объекты. В то время как объекты продолжали свое существование. Ну а на момент завершения сценария, как мы знаем, освобождаются все ресурсы, вот и получаем в конце вызовы деструкторов.
Теперь попробуйте закомментировать строчки, где идет создание внутренних перекрестных ссылок:

// $first->setNext( $second);
// $second->setNext( $first );


В результате получаем следующий результат:

constructor
constructor
destructor -> $first
destructor -> $second
Debug


Отсюда видим, что теперь наши объекты спокойно уничтожаются, что подтверждается сообщениями от их деструкторов до слова Debug. Все верно, ведь теперь на них ничто и никто не ссылается, вот и срабатывает сборщик мусора. Обратите внимание в описании класса Node на метод setNext() который работает непосредственно со ссылками. Всем удачи!