Moment.js: легкая работа с датами


    Moment.js это отличная библиотека для работы с датами в JavaScript. Примеры под катом.

    var now = moment();
    moment.lang('ru');
    console.log(now.format('dddd, MMMM DD YYYY, h:mm:ss'));
    // вторник, ноябрь 15 2011, 3:31:03
    


    var halloween = moment([2011, 9, 31]); // October 31st
    moment.lang('ru');
    console.log(halloween.fromNow());
    // 16 дней назад
    


    var now = moment().add('days', 9);
    moment.lang('ru');
    console.log(now.format('dddd, MMMM DD YYYY'));
    // четверг, ноябрь 24 2011
    


    var now = moment();
    moment.lang('ru');
    console.log(now.format('LLLL'));
    // вторник, 15 ноябрь 2011 15:27
    


    Ну и собственно ссылки:
    Офсайт | Документация | github

    P.S. На мой взгляд самая адекватная либа по работе с датами. Осталось только допилить нормальную поддержку русского языка.
    Share post

    Comments 90

      +16
      >> var halloween = moment([2011, 9, 31]); // October 31st

      Юзабельно блин…
        –2
        Английский формат даты, что поделать.
          +7
          Я не на формате заострял внимание, а на то, что как и в стандартном Date отсчет месяцев ведется с 0, а дней с 1. То есть никакого улучшения тут библиотека не привнесла.
            0
            Стандарты лучше не ломать, даже если они кривые (
              +1
              Тогда какой смысл в обертке? Стандартный класс даже локализацию умеет.
                0
                Ну не заменой нумерацией месяца живы )
              0
              Не знаю, я уже привык, мне теперь месяц с единицы начинать — не юзабельно :)
            0
            9-й месяц — сентябрь, а не октябрь, как это отмечено в комментарии к коду.
          +4
          А Datejs чем неадекватна?
            +3
            Расширением встроенных классов как минимум.
              +2
              А вы можете назвать хотя бы один аргумент (именно аргумент, а не религиозную чушь) против этого?
                +5
                Да без проблем.
                Например если человек видит
                var now = moment();
                console.log(now.format('dddd, MMMM DD YYYY, h:mm:ss'));
                

                и
                // Set to 8:30 AM on the 15th day of the month
                Date.today().set({ day: 15, hour: 8, minute: 30 });
                

                Во втором случае явно видно использование сторонней библиотеки.

                Для меня этого достаточно.
                  +5
                  Прошу прощения — в первом случае.
                    +7
                    явно видно использование сторонней библиотеки.

                    И что? Какая разница, библиотека добавляет свойство в объект window или в объект Date?
                      +4
                      Различия в ожидании поведения объектов.

                      Например на текущем проекте болталось две либы: datejs и еще одна, которая расширяет свойства. В итоге вычленять этот мэшап из разных частей кода вышло достаточно затратно.

                      Или же например получая method not defined у Date можно долго чесать затылок ища этот несуществующий метод в ECMA.
                        +3
                        Всё равно аргументы непонятны. Если либа подключена, то где взялся «method not defined»? Если не подключена, то тем более.
                          +3
                          Я говорю о том что если не подключена то найти проблему будет сложнее.
                          И что? Какая разница, библиотека добавляет свойство в объект window или в объект Date?

                          Это с точки зрения семантики — никакой.
                          С точки зрения расширения существующего класса или добавления нового в контекст global есть.

                          Вообще странно видеть подобные вопросы от человека, который ищет js разработчика.
                          И кстати хотелось бы увидеть встречные доводы, а то сейчас я вижу какие-то нонконформистские высказывания без обоснования.
                            +4
                            Вы бы ещё мои топики почитали, перед тем, как судить негативно.
                            Просто я до сих пор не видел ни одного серьёзного аргумента против расширения прототипов.
                            Все какие-то религиозные.

                            Это удобно, быстро, коротко. Это соответствует всей идеологии JS. Этим пользуются все JS фреймворки. Даже jQuery, хотя и не расширяет встроенные прототипы, но плагины для него пишутся именно расширением прототипа.
                              +9
                              Это не религия. Это здравый смысл для больших проектов.
                              Вы используете «быстро и коротко» здесь и сейчас, рискуя напороться на грабли позже.
                              Как минимум лучше сделать класс-наследник и работать с ним. Или как в либе топика оберткой.
                              И лучше не путать плагины с классами. Это совершенно разные вещи.
                                +2
                                Именно, JS ведь не компилируемый (в IDE), это не Java где можно двумя кликами отследить всю иерархию наследования и вызовов любых методов, тут в илеале нужно держать всю иерархию в голове, а это не всегда возможно.

                                Как минимум 2 аргумента:
                                — Более явный вызов расширенных методов, легче отслеживать, рефакторить.
                                — Гарантия отсутствия «конкурирования» за одноименный методы/поля при подключении разных библиотек

                                Мне приходилось рефакторить веб часть больших проектов (JEE/J2EE), и я вполне понимаю и принимаю приведенную аргументацию.
                                  +1
                                  Не соглашусь с вами. Расширять встроенные типы можно, но не все, например прототип Object я бы трогать никогда не стал, прототипы DOM элементов тоже. А, например, Data и Array вполне успешно поддаются расширению.

                                  А чесать голову при ошибке не придется, т.к. достаточно взглянуть на список методов в mdn, да и небольшой он, чтобы в нем путаться. В этом случае not defined на родном объекте ничем не отличается от такого же сообщения на любом другом.
                                    0
                                    Думаю что опытный проектировщик / архитектор / просто разработчик (в exUSSR бывает что это одно лицо) основываясь на своем и чужом опыте не станет использовать (только по той причине что «так сделать можно» и что так проще и быстрее) конструкции/методы/приемы/структуры которые по своей сути допускают проблемы.

                                    Зачем изначально залаживать в разработку приложения опцию «кому-то придется лишний раз смотреть в mdn, а то и не только в mdn» когда этого можно избежать. Да и not defined не единственная особенность, другая проблема в пересечении функционала, если утрировано то типа как запустить вместе Mootools и Prototype :)

                                    Вопрос не только в том чтобы сделать, но и в дальнейшей поддержке/развитии проекта при условии что разработку ведут разные люди/команды. Каждый из этих разработчиков может захотеть добавить в проект своих плюшек модифицирующих базовые классы. При этом если этот разработчик (любящий расширять базовые классы) ответственный ему придется смотреть все другие «чужие» исходники и проверять и тестировать не будет ли его код конфликтовать с чужими расширениями базовых классов. Думаете кто-то пойдет на это, или лучше выберет путь автономных самодостаточных расширяемых модулей?

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

                                    Разумеется в принципе расширять базовые классы можно, вопрос в том насколько разумно это делать.
                                  +2
                                  Вы слышали про проблему Prototype.js и getElementsByClassName?
                                    +1
                                    Слышал. Аналогично с .bind. И что? jQuery не расширяет прототипы, но всё-равно имеет обратную несовместимость и ломается в новых браузерах. Я уж молчу о том, что до сих пор большинство фреймворков работают не согласно спецификации querySelectorAll.

                                    А старые версии некорректно работают в новых браузерах. У меня есть скрипты, которые плохо работают в IE9 из-за того, что в фреймворке, на котором я их писал не учтено, что может появится новый IE, который похож на остальные современные браузеры. А не могу перейти на новую версию из-за нарушенной обратной совместимости. И не в расширенных прототипах дело.

                                    Да, мир меняется, вводятся новые стандарты, если код не поддерживать, то высока вероятность, что он не будет работать в новых браузерах. И расширение прототипов никак не меняет эту вероятность.
                                      +1
                                      jQuery имеет обратную несовместимость с самим собой, это нормально. Вы контралируете обновление jQuery.

                                      А насчёт «ломается в новых браузерах» я бы хотел цитату.
                                      И даже если и правда иногда ломается, разумеется, расширение прототипов является дополнительным риском и меняет эту вероятность в большую сторону.
                                        0
                                        До версии 1.5.1 jQuery не работает в IE9
                                          +1
                                          Как-то лениво вы пользуетесь поиском. Настоящая ссылка.

                                          Этот баг — это баг. Т.е. разработчики допустили оплошность и потом исправили.
                                          Баги с расширением прототипов — это неправильные архитектурные решения. Их исправить сложно.

                                          К примеру, случилась такая проблема, как у prototype.js — что делать? Старый код зависим от старого поведения, а новый код (особенно, внешний) — от нового.
                                          Как догадаться, какой метод нужен вызывающему коду?
                                  • UFO just landed and posted this here
                                      0
                                      Да религия она такая, все крутится вокруг веры, понимать не нужно или невозможно. Но к счастью в JS религии дела обстоят немного по другому, некоторые адепты все же смогли постигнуть нирвану :)
                                      +2
                                      Давай представим одну очень простую ситуацию.
                                      1. Я(Самый умный, хозяин СВОЕГО кода) подключаю тебя(супер пупер библиотеку)
                                      2. Ты расширяешь какие-то мои(МОИ!) прототипы.
                                      3. Все падает.
                                      Почему?
                                      ответ: потому что я, самый такой умный, хозяин своего кода, кроме тебя подключил еще 10 библиотек, к тому же самостоятельно расширил интересные мне обьекты.
                                      После чего пришол ты и часть моих изменений перетер.

                                      Тут, так уж получается, лучше ум самому проверять тот же String.trim(Array.each\map\bind\....) на то что они native, а не просто есть.
                                      +4
                                      Поддерживаю. Мне тоже не нравится когда всякие либы засерают встроенные классы. Готов мирится с теми что добавляют не хватающих методов браузерам типа старых IE (типа each и тд), то есть приводят поведение к некоторому стандарту, все остальное пихать в свои обертки (неймспейсы/замыкания).

                                      Представьте что будет если всякая либа захочет расширять встроенные классы, одна, вторая, третья, и наступит неминуемый хаос, библиотеки начнут перетирать методы друг дружки меняя ожидаемое поведение, будет весело :)
                                        +2
                                        Вы преувеличиваете. В тех же рубях все нормально с этим.
                                          0
                                          Рубисты на свой код пишут тесты чтобы избежать вышеуказанных проблем.

                                          По поводу расширения прототипов vs заварачивания:

                                          _(_(somethingsomething + _($(something)).pluck(_($(olo).attr(trololo)).detect(something)))))

                                          может кому то нравится этот недо-лисп но я бы в своем проекте держал бы методы из underscore в прототипах.

                                          Пишите бля тесты и не ссыте.
                                • UFO just landed and posted this here
                                  • UFO just landed and posted this here
                                    • UFO just landed and posted this here
                                        0
                                        Это аргумент, чтобы конкретно не заниматься расширением прототипа Object
                                          –1
                                          И Array разумеется.
                                            –1
                                            Приведите, пожалуйста, пример, когда все может развалиться, если расширен прототип Array
                                                –1
                                                var a = [12, 14, 13, 6];
                                                Аrray лучше пробегать так
                                                for(var i = 0, i < a.length; ++i){
                                                  console.log(i, a[i]);
                                                }
                                                

                                                это куда быстрей и не влечет тех проблем о которых вы говорите
                                                ну на крайний случай так
                                                a.forEach(function(v,i){
                                                  console.log(i, v);
                                                });
                                                
                                                  0
                                                  Ну у меня везде for разумеется.
                                                  Но этот вариант тоже имеет право жить.
                                                  PS Ваш второй вариант не работает без патчинга.
                                                  • UFO just landed and posted this here
                                                      +1
                                                      Потому, что удобный вам синтаксический сахар предназначен для того, чтобы пробегать по свойствам объекта, а не по элементам массива, для второго есть forEach.
                                                      • UFO just landed and posted this here
                                                    +2
                                                    for in — это, мягко говоря, не естественный способ обходить массив.
                                              • UFO just landed and posted this here
                                                  +1
                                                  No offence, но по личным наблюдениям виновато большое комьюнити и jQuery.
                                                  Куча дизайнеров, которым нужно допилить плагин или прикрутить мигающую штуку делают свое дело.
                                                  В питоне же средний уровень разработчика на порядок выше, и соответственно если ты просишь совета, то чаще всего тебе не только скажут но еще и в целом совета дадут по общей архитектуре.
                                                    +1
                                                    Пример с тримом чудесный. Находясь в десятом замыкании (желательно, что бы в каждом было по пачке переменных) и вызывая трим в цикле можно наблюдать как яваскрипт ищет трим по всем областям видимости каждый раз. String расширять не сильно плохо, вот за Object надо мучительно убивать. А пихнуть в Date то что связано с работой с датой и нужно в синглтоне — вполне логично.
                                                    • UFO just landed and posted this here
                                        0
                                      +7
                                      >> А Datejs чем неадекватна?
                                      Last updated 2008-04-14
                                        +4
                                        железобетонно :)
                                      0
                                      Библиотека выглядит хорошо, актуально и разумно. Но вопрос переписывания всего кода проекта заставляет задуматься…
                                        +3
                                        Ну я полагаю текущий проект — не последний ;)
                                          0
                                          Подумал о том же, то есть поменять библиотеку с Datejs (на то время ничего больше не попалось готового) на Moment. Проблема в том что Datejs расширяет встроенный класс и так просто отловить все ее добавки по всему проекту не получится (проект делался не одним поколением людей, и не все они были разработчиками судя по коду). Но в нашем случае весь «не стандартный» функционал либы Datejs используется только через свою обертку (типа CommonUtils.Date.format) так что поменять имплентацию на Moment не должно быть сложно :)
                                          +3
                                          Читаю доки не вижу ни одного слова про таймзоны, а без них такие примеры типа такого

                                          moment().add('hours', 1).fromNow()

                                          выглядят наивно
                                            0
                                            В Вашем примере будет использоваться текущая зона (new Date()).
                                            Проблемы будут когда будет использован массив

                                            moment([2011, 11, 15, 17, 11]).add('hours', 1).fromNow()

                                            Так как в документации сказано что используется как обертка для Date.UTC

                                            А вообще да, думаю стоит завести тикет на более прозрачную обработку зон.
                                              0
                                              Хотя нужно глянуть исходники
                                              Может на самом деле там корректная обработка всего этого, и им просто нужно добавить таймзону в их конструктор.
                                              +1
                                              А мне в этом примере не нравится строка 'hours', я бы вынес в константы типа moment.HOURS, moment.MILLISECONDS и тд.
                                                +1
                                                Да, константы определенно лучше.
                                                  +2
                                                  Надеюсь аргументации не попросят :)
                                              +1
                                              Если используешь mootools (как я), то там есть чудесный класс для работы с датами, который покрывает любые потребности.
                                                –1
                                                [irony]Только DOM, только хардкор[/irony]
                                                  0
                                                  Который является мутулзной оберткой над date.js. И, кстати, этот класс в mootools.more.
                                                  0
                                                  var halloween = moment([2011, 9, 31]); \\ October 31st
                                                  Октябрь — десятый месяц вроде?
                                                    0
                                                    developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date
                                                    month
                                                    Integer value representing the month, beginning with 0 for January to 11 for December.
                                                      +3
                                                      Но удобнее было бы сделать в конструкторе, чтобы второй аргумент совпадал с номером месяца. Тогда меньше путаницы.
                                                        +2
                                                        это они зря :)
                                                          0
                                                          Это они специально (
                                                            0
                                                            Это для удобства переименования месяцев
                                                            var month = ['января', 'февраля'...]
                                                            var date = new Date();
                                                            alert(month[date.getMonth()]);

                                                            Вот только мне действительно не понятно почему в стандартном классе Date, getMonth/Hour/Minutes — вернуть месяц/часы/секунды и т.п., а getDay — вернуть день недели. День месяца же возвращатся getDate — что переводится вернуть дату, что как-то глупо и не логично
                                                              +5
                                                              Да прям уж…
                                                              var month = ['', 'января', 'февраля'...]
                                                              и все дела.
                                                      +1
                                                      В JS есть всроенный объект для работы с датами. Зачем утяжелять все лишними билиотеками, тем более в которую заложено 30 языков, из которых используется только 1. Никогда этого не понимал.
                                                        0
                                                        О каких 30 языках идет речь?
                                                          0
                                                          > В JS есть всроенный объект для работы с датами.

                                                          Прибавьте 2 дня к текущей дате или вычислите разницу в днях между двумя датами, используя встроенный объект. Потом замените дни на недели, месяцы, годы.
                                                          0
                                                          Видно, что у автора данного топика по сочинениям в школе было 5.
                                                          Голые примеры и пару строк отсебятины.
                                                          Неплохо было бы написать, кто автор, когда он написал её, где используется в больших проектах (если используется).
                                                          Извините, ничего личного.
                                                            +1
                                                            Мне такой вид топиков наиболее информативен. Предназначение, примеры, ссылки на документацию.
                                                            И так информации куча лишней отовсюду.
                                                              0
                                                              Сначала нужно получить представление о инструменте (именно эта информация и представлена), а потом уже если он (инструмент) заслужил и если будет необходимость или просто интерес (по поводу того что либа понравилась или наоборот) смотреть кто автор. Зачем нам лишняя информация. Авторитет или просто известность автора и популярность инструмента не всегда решают.
                                                              0
                                                              И почему встроенный Date этого не умеет? Что, редко приходится с датой работать в js? Маразм…
                                                              А за либу спасибо, выглядит юзабельн и всего пару кб.
                                                                0
                                                                Наболело. Хотелось бы, чтобы для всех языков и платформ использовался один стандарт пользовательских формат дат (e.g. yy, MM, mm ss tokens). Иногда необходимо интегрировать, к примеру, (JS) jQuery(foo).datepicker({dateFormat:bar}) с (.NET) HttpContext.Culture.DateTimeFormatInfo.ShortDatePattern. И тут въезжает на сцену серебристый велосипед, рама — карбон, 24 скорости. Если кто знает хороший и готовый подход, приветствую статью, буду плюсовать и в хвост и в гриву
                                                                  +1
                                                                  Вот Вам стандарт www.w3.org/TR/NOTE-datetime
                                                                  Приводите к нему.
                                                                    0
                                                                    Нехорошо, зачем вы меня вводите в заблуждение? Это всего лишь примечание, которое консорциум опубликовал для обсуждения в 1997 году и не одобрял его с того времени.

                                                                    И содержит очень узкий набор возможных паттернов форматирования, не отображающих современные нужды.

                                                                  0
                                                                  Поддержки дат в формате ISO 8601 нету, жаль. Я вменяемый парсер ISO даты на Javascript так и не нашел, увы :(
                                                                  Библиотечка хорошая, взял на заметку, спасибо.
                                                                    0
                                                                    Вас именно что именно интересует? Парсинг?
                                                                    Ну так самому можно же массив для парсинга накидать за пару минут из вики.
                                                                      0
                                                                      Хотелось просто поддержки «из коробки». ISO стандарт достаточно многообразен, простой массив не пойдет.
                                                                      Хочется чтобы нормально воспринимались форматы как, например 2011-11-15T22:34:42Z, так и 2011-11-15Т22:34:42+03, без лишних телодвижений.
                                                                      0
                                                                      var day = moment("12-25-1995", ["MM-DD-YYYY", "YYYY-MM-DD"]);
                                                                      

                                                                      String + Formats
                                                                      0
                                                                      Спасибо.

                                                                      Only users with full accounts can post comments. Log in, please.