Где можно найти документацию по форматированию даты в JavaScript?


14 Answers

momentjs

Это (легкая) * библиотека дат JavaScript для синтаксического анализа, управления и форматирования дат.

var a = moment([2010, 1, 14, 15, 25, 50, 125]);
a.format("dddd, MMMM Do YYYY, h:mm:ss a"); // "Sunday, February 14th 2010, 3:25:50 pm"
a.format("ddd, hA");                       // "Sun, 3PM"

(*) легкое значение 9.3KB minified + gzipped в наименьшей возможной настройке (feb 2014)

Question

Я заметил, что new Date() функция new Date() JavaScript очень умна в принятии дат в нескольких форматах.

Xmas95 = new Date("25 Dec, 1995 23:15:00")
Xmas95 = new Date("2009 06 12,12:52:39")
Xmas95 = new Date("20 09 2006,12:52:39")

Я не мог найти документацию в любом месте, показывающую все допустимые строковые форматы при вызове new Date() .

Это для преобразования строки в дату. Если мы посмотрим на противоположную сторону, то есть преобразуем объект даты в строку, до сих пор у меня создалось впечатление, что JavaScript не имеет встроенного API для форматирования объекта даты в строку.

Примечание редактора: Следующий подход - попытка акитера, которая работала в определенном браузере, но не работает вообще; см. ответы на этой странице, чтобы увидеть некоторые актуальные решения.

Сегодня я играл с методом toString() в объекте даты и, на удивление, он служит для форматирования даты для строк.

var d1 = new Date();
d1.toString('yyyy-MM-dd');       //Returns "2009-06-29" in Internet Explorer, but not Firefox or Chrome
d1.toString('dddd, MMMM ,yyyy')  //Returns "Monday, June 29,2009" in Internet Explorer, but not Firefox or Chrome

Также здесь я не мог найти никакой документации по всем способам форматирования объекта даты в строку.

Где находится документация, в которой перечислены спецификаторы формата, поддерживаемые объектом Date() ?




Just to continue gongzhitaao's solid answer - this handles AM/PM

 Date.prototype.format = function (format) //author: meizz
{
    var hours = this.getHours();
    var ttime = "AM";
    if(format.indexOf("t") > -1 && hours > 12)
    {
        hours = hours - 12;
        ttime = "PM";
     }

var o = {
    "M+": this.getMonth() + 1, //month
    "d+": this.getDate(),    //day
    "h+": hours,   //hour
    "m+": this.getMinutes(), //minute
    "s+": this.getSeconds(), //second
    "q+": Math.floor((this.getMonth() + 3) / 3),  //quarter
    "S": this.getMilliseconds(), //millisecond,
    "t+": ttime
}

if (/(y+)/.test(format)) format = format.replace(RegExp.$1,
  (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o) if (new RegExp("(" + k + ")").test(format))
    format = format.replace(RegExp.$1,
      RegExp.$1.length == 1 ? o[k] :
        ("00" + o[k]).substr(("" + o[k]).length));
return format;
}



Вы можете просто расширить объект Date с помощью метода нового format как указано meizz , ниже приведен код автора. И вот jsfiddle .

Date.prototype.format = function(format) //author: meizz
{
  var o = {
    "M+" : this.getMonth()+1, //month
    "d+" : this.getDate(),    //day
    "h+" : this.getHours(),   //hour
    "m+" : this.getMinutes(), //minute
    "s+" : this.getSeconds(), //second
    "q+" : Math.floor((this.getMonth()+3)/3),  //quarter
    "S" : this.getMilliseconds() //millisecond
  }

  if(/(y+)/.test(format)) format=format.replace(RegExp.$1,
    (this.getFullYear()+"").substr(4 - RegExp.$1.length));
  for(var k in o)if(new RegExp("("+ k +")").test(format))
    format = format.replace(RegExp.$1,
      RegExp.$1.length==1 ? o[k] :
        ("00"+ o[k]).substr((""+ o[k]).length));
  return format;
}

alert(new Date().format("yyyy-MM-dd"));
alert(new Date("january 12 2008 11:12:30").format("yyyy-MM-dd h:mm:ss"));



Personally, because I use both PHP and jQuery/javascript in equal measures, I use the date function from php.js http://phpjs.org/functions/date/

Using a library that uses the same format strings as something I already know is easier for me, and the manual containing all of the format string possibilities for the date function is of course online at php.net

You simply include the date.js file in your HTML using your preferred method then call it like this:

var d1=new Date();
var datestring = date('Y-m-d', d1.valueOf()/1000);

You can use d1.getTime() instead of valueOf() if you want, they do the same thing.

The divide by 1000 of the javascript timestamp is because a javascript timestamp is in miliseconds but a PHP timestamp is in seconds.




Пример кода:

var d = new Date();
var time = d.toISOString().replace(/.*?T(\d+:\d+:\d+).*/, "$1");

Вывод:

"13:45:20"




JsSimpleDateFormat is a library that can format the date object and parse the formatted string back to Date object. It uses the Java format (SimpleDateFormat class). The name of months and days can be localized.

Пример:

var sdf = new JsSimpleDateFormat("EEEE, MMMM dd, yyyy");
var formattedString = sdf.format(new Date());
var dateObject = sdf.parse("Monday, June 29, 2009");



The library sugar.js has some great functionality for working with dates in JavaScript. And it is very well documented .

Sugar gives the Date class much love starting with the Date.create method which can understand dates in just about any format in 15 major languages, including relative formats like "1 hour ago". Dates can also be output in any format or language using an easy to understand syntax, with shortcuts to commonly used date formats. Complex date comparison is also possible with methods like is, which understand any format and apply built in precision.

A few examples:

Date.create('July 4, 1776')  -> July 4, 1776
Date.create(-446806800000)   -> November 5, 1955
Date.create(1776, 6, 4)      -> July 4, 1776
Date.create('1776年07月04日', 'ja') -> July 4, 1776
Date.utc.create('July 4, 1776', 'en')  -> July 4, 1776

Date.create().format('{Weekday} {d} {Month}, {yyyy}')    -> Monday July 4, 2003
Date.create().format('{hh}:{mm}')                        -> 15:57
Date.create().format('{12hr}:{mm}{tt}')                  -> 3:57pm
Date.create().format(Date.ISO8601_DATETIME)              -> 2011-07-05 12:24:55.528Z

Date.create().is('the 7th of June') -> false
Date.create().addMonths(2); ->"Sunday, June 15, 2014 13:39"



All browsers

The most reliable way to format a date with the source format you're using, is to apply the following steps :

  1. Use new Date() to create a Date object
  2. Use .getDate() , .getMonth() and .getFullYear() to get respectively the day, month and year
  3. Paste the pieces together according to your target format

Пример :

var date = '2015-11-09T10:46:15.097Z';

function format(input) {
    var date = new Date(input);
    return [
       ("0" + date.getDate()).slice(-2),
       ("0" + (date.getMonth()+1)).slice(-2),
       date.getFullYear()
    ].join('/');
}

document.body.innerHTML = format(date); // OUTPUT : 09/11/2015

(See also this Fiddle ).

Modern browsers only

You can also use the built-in .toLocaleDateString method to do the formatting for you. You just need pass along the proper locale and options to match the right format, which unfortunately is only supported by modern browsers (*) :

var date = '2015-11-09T10:46:15.097Z';

function format(input) {
    return new Date(input).toLocaleDateString('en-GB', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit'
    });
}

document.body.innerHTML = format(date); // OUTPUT : 09/11/2015

(See also this Fiddle ).

(*) According to the MDN , "Modern browsers" means Chrome 24+, Firefox 29+, IE11, Edge12+, Opera 15+ & Safari nightly build




The correct way to format a date to return "2012-12-29" is with the script from JavaScript Date Format :

var d1 = new Date();
return d1.format("dd-m-yy");

This code does NOT work:

var d1 = new Date();
d1.toString('yyyy-MM-dd');      



Где находится документация, в которой перечислены спецификаторы формата, поддерживаемые объектом Date() ?

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

AFAIK, чистый JavaScript не поддерживает спецификаторы формата так, как вы указали, что хотите их использовать . Но он поддерживает методы форматирования дат и / или времени, такие как .toLocaleDateString() , .toLocaleTimeString() и .toUTCString() .

Ссылка на объект Date я использую чаще всего, находится на w3schools.com/jsref/jsref_obj_date.asp (но быстрый поиск в Google выявит много других, которые могут лучше соответствовать вашим потребностям).

Также обратите внимание, что в разделе « Свойства объекта даты » содержится ссылка на prototype , который иллюстрирует некоторые способы продления объекта Date с помощью специальных методов. На протяжении многих лет в сообществе JavaScript обсуждались, действительно ли это лучшая практика, и я не выступаю за нее или против нее, просто указывая на ее существование.




Короткий ответ

Нет никакой «универсальной» документации, к которой подходит javascript; каждый браузер, у которого есть javascript, действительно является реализацией. Однако есть стандарт, который, как правило, придерживаются большинство современных браузеров, и это стандарт EMCAScript; стандартные строки ECMAScript, в минимальном случае, должны были бы модифицировать реализацию определения ISO 8601.

В дополнение к этому есть второй стандарт, установленный IETF который, как правило, также IETF браузеры, что является определением временных меток, сделанных в RFC 2822. Фактическая документация может быть найдена в списке ссылок внизу.

Из этого вы можете ожидать базовые функциональные возможности, но то, что должно «быть», не является неотъемлемой частью того, что «есть». Я собираюсь немного углубиться в эту процедуру, хотя, как кажется, только три человека действительно ответили на вопрос (Скотт, goofballLogic и peller именно), которые, как мне кажется, указывают на то, что большинство людей не знают, что на самом деле происходит, когда вы создайте объект Date.

Длительный ответ

Где находится документация, в которой перечислены спецификаторы формата, поддерживаемые объектом Date ()?


Чтобы ответить на вопрос или, как правило, даже искать ответ на этот вопрос, вам нужно знать, что javascript не является новым языком; это фактически реализация ECMAScript и соответствует стандартам ECMAScript (но обратите внимание, что javascript также на самом деле заранее подготовлен к этим стандартам, стандарты EMCAScript построены на ранней реализации LiveScript / JavaScript). Текущий стандарт ECMAScript - 5,1 (2011 год); в то время, когда вопрос был первоначально задан (июнь 2009 года), стандарт был 3 (4 были оставлены), но 5 был выпущен вскоре после публикации в конце 2009 года. Это должно указать одну проблему; какой стандарт может реализоваться в javascript, может не отражать то, что на самом деле существует, потому что: а) это реализация данного стандарта; б) не все реализации стандарта пуританские, а в) функциональность не выдается синхронно с новый стандарт, поскольку d) реализация - постоянная работа

По сути, при работе с javascript вы имеете дело с производным (javascript, специфичным для браузера) реализации (сам javascript). Google V8, например, реализует ECMAScript 5.0, но JScript от Internet Explorer не пытается соответствовать стандарту ECMAScript, но Internet Explorer 9 соответствует ECMAScript 5.0.

Когда один аргумент передается новой Date (), он запускает этот прототип функции:

new Date(value)

Когда два или более аргументов передаются новой Date (), он запускает этот прототип функции:

new Date (year, month [, date [, hours [, minutes [, seconds [, ms ] ] ] ] ] )


Обе эти функции должны выглядеть знакомыми, но это не сразу отвечает на ваш вопрос и то, что количественно, как приемлемый «формат даты», требует дальнейшего объяснения. Когда вы передаете строку новой Date (), она вызывается прототипом (обратите внимание, что я использую прототип слова свободно, версии могут быть отдельными функциями или могут быть частью условного оператора в одной функции) для новую дату (значение) с вашей строкой в ​​качестве аргумента для параметра «значение». Эта функция сначала проверит, является ли это числом или строкой. Документацию по этой функции можно найти здесь:

http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.3.2

Из этого можно сделать вывод, что для получения форматирования строк, разрешенного для новой Date (value), мы должны посмотреть на метод Date.parse (string). Документацию по этому методу можно найти здесь:

http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.4.2

Кроме того, мы можем заключить, что ожидается, что даты будут в модифицированном расширенном формате ISO 8601, как указано здесь:

http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15

Однако, по опыту, мы можем признать, что объект Date в javascript принимает другие форматы (в первую очередь связанные с существованием этого вопроса), и это нормально, потому что ECMAScript допускает конкретные форматы реализации. Тем не менее, это все еще не отвечает на вопрос о том, какая документация доступна в доступных форматах, и какие форматы фактически разрешены. Мы рассмотрим реализацию javascript Google, V8; обратите внимание, я не предлагаю, чтобы это был «лучший» механизм javascript (как можно определить «лучший» или даже «хороший»), и нельзя предположить, что форматы, разрешенные в V8, представляют все доступные сегодня форматы, но я думаю, что это справедливо предположить, что они следуют современным ожиданиям.

Google V8, date.js, DateConstructor

https://code.google.com/p/v8/source/browse/trunk/src/date.js?r=18400#141

Рассматривая функцию DateConstructor, мы можем найти, что нам нужно найти функцию DateParse; однако, обратите внимание, что «год» не является фактическим годом и является лишь ссылкой на параметр «год».

Google V8, date.js, DateParse

https://code.google.com/p/v8/source/browse/trunk/src/date.js?r=18400#270

Это вызывает% DateParseString, которая на самом деле является ссылкой на функцию времени выполнения для функции C ++. Это относится к следующему коду:

Google V8, runtime.cc,% DateParseString

https://code.google.com/p/v8/source/browse/trunk/src/runtime.cc?r=18400#9559

Вызов функции, с которым мы связаны в этой функции, относится к DateParser :: Parse (); игнорируйте логику, связанную с этими вызовами функций, это просто проверки, соответствующие типу кодирования (ASCII и UC16). DateParser :: Parse определяется здесь:

Google V8, dateparser-inl.h, DateParser :: Parse

https://code.google.com/p/v8/source/browse/trunk/src/dateparser-inl.h?r=18400#36

Это функция, которая фактически определяет, какие форматы она принимает. По сути, он проверяет стандарт EMCAScript 5.0 ISO 8601 и, если он не соответствует стандартам, тогда он попытается создать дату на основе устаревших форматов. Несколько ключевых моментов, основанных на комментариях:

  1. Слова до того, как первое число, неизвестное синтаксическому анализатору, игнорируется.
  2. Воспроизведение в скобках игнорируется.
  3. Беззнаковые числа, за которыми следуют «:», интерпретируются как «компонент времени».
  4. Беззнаковые числа, за которыми следует «.», Интерпретируются как «компонент времени» и должны сопровождаться миллисекундами.
  5. Подписанные номера, за которыми следует часовой или час (например, +5: 15 или +0515), интерпретируются как часовой пояс.
  6. При объявлении часа и минуты вы можете использовать либо «hh: mm», либо «hhmm».
  7. Слова, обозначающие часовой пояс, интерпретируются как часовой пояс.
  8. Все остальные номера интерпретируются как «компоненты даты».
  9. Все слова, начинающиеся с первых трех цифр месяца, интерпретируются как месяц.
  10. Вы можете определить минуты и часы вместе в любом из двух форматов: «hh: mm» или «hhmm».
  11. Символы типа «+», «-» и «Непревзойденные») не допускаются после обработки номера.
  12. Элементы, которые соответствуют нескольким форматам (например, 1970-01-01), обрабатываются как стандартная строка стандарта EMCAScript 5.0 ISO 8601.

Поэтому этого должно быть достаточно, чтобы дать вам общее представление о том, что ожидать, когда дело доходит до передачи строки в объект Date. Вы можете дополнительно расширить это, посмотрев следующую спецификацию, которую Mozilla указывает на сеть разработчиков Mozilla (соответствует меткам времени IETF RFC 2822):

http://tools.ietf.org/html/rfc2822#page-14

В Microsoft Developer Network дополнительно упоминается дополнительный стандарт для объекта Date: ECMA-402, спецификация API интернационализации ECMAScript, которая дополняет стандарт ECMAScript 5.1 (и будущие). Это можно найти здесь:

http://www.ecma-international.org/ecma-402/1.0/

В любом случае, это должно помочь подчеркнуть, что нет «документации», которая универсально представляет все реализации javascript, но имеется достаточно документации для разумного понимания того, какие строки приемлемы для объекта Date. Довольно загруженный вопрос, когда вы думаете об этом, да? :П

Рекомендации

http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.3.2

http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.4.2

http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15

http://tools.ietf.org/html/rfc2822#page-14

http://www.ecma-international.org/ecma-402/1.0/

https://code.google.com/p/v8/source/browse/trunk/src/date.js?r=18400#141

https://code.google.com/p/v8/source/browse/trunk/src/date.js?r=18400#270

https://code.google.com/p/v8/source/browse/trunk/src/runtime.cc?r=18400#9559

https://code.google.com/p/v8/source/browse/trunk/src/dateparser-inl.h?r=18400#36

Ресурсы

developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

http://msdn.microsoft.com/en-us/library/ff743760(v=vs.94).aspx




Вот функция, которую я использую много. Результат - yyyy-mm-dd hh: mm: ss.nnn.

function date_and_time() {
    var date = new Date();
    //zero-pad a single zero if needed
    var zp = function (val){
        return (val <= 9 ? '0' + val : '' + val);
    }

    //zero-pad up to two zeroes if needed
    var zp2 = function(val){
        return val <= 99? (val <=9? '00' + val : '0' + val) : ('' + val ) ;
    }

    var d = date.getDate();
    var m = date.getMonth() + 1;
    var y = date.getFullYear();
    var h = date.getHours();
    var min = date.getMinutes();
    var s = date.getSeconds();
    var ms = date.getMilliseconds();
    return '' + y + '-' + zp(m) + '-' + zp(d) + ' ' + zp(h) + ':' + zp(min) + ':' + zp(s) + '.' + zp2(ms);
}



If you don't need all the features that a library like momentjs provides, then you can use my port of strftime . It's lightweight (1.35 KB vs. 57.9 KB minified compared to Moment.js 2.15.0) and provides most of the functionality of strftime() .

/* Port of strftime(). Compatibility notes:
 *
 * %c - formatted string is slightly different
 * %D - not implemented (use "%m/%d/%y" or "%d/%m/%y")
 * %e - space is not added
 * %E - not implemented
 * %h - not implemented (use "%b")
 * %k - space is not added
 * %n - not implemented (use "\n")
 * %O - not implemented
 * %r - not implemented (use "%I:%M:%S %p")
 * %R - not implemented (use "%H:%M")
 * %t - not implemented (use "\t")
 * %T - not implemented (use "%H:%M:%S")
 * %U - not implemented
 * %W - not implemented
 * %+ - not implemented
 * %% - not implemented (use "%")
 *
 * strftime() reference:
 * http://man7.org/linux/man-pages/man3/strftime.3.html
 *
 * Day of year (%j) code based on Joe Orost's answer:
 * http://.com/questions/8619879/javascript-calculate-the-day-of-the-year-1-366
 *
 * Week number (%V) code based on Taco van den Broek's prototype:
 * http://techblog.procurios.nl/k/news/view/33796/14863/calculate-iso-8601-week-and-year-in-javascript.html
 */
function strftime(sFormat, date) {
  if (!(date instanceof Date)) date = new Date();
  var nDay = date.getDay(),
    nDate = date.getDate(),
    nMonth = date.getMonth(),
    nYear = date.getFullYear(),
    nHour = date.getHours(),
    aDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
    aMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
    aDayCount = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
    isLeapYear = function() {
      if (nYear&3!==0) return false;
      return nYear%100!==0 || year%400===0;
    },
    getThursday = function() {
      var target = new Date(date);
      target.setDate(nDate - ((nDay+6)%7) + 3);
      return target;
    },
    zeroPad = function(nNum, nPad) {
      return ('' + (Math.pow(10, nPad) + nNum)).slice(1);
    };
  return sFormat.replace(/%[a-z]/gi, function(sMatch) {
    return {
      '%a': aDays[nDay].slice(0,3),
      '%A': aDays[nDay],
      '%b': aMonths[nMonth].slice(0,3),
      '%B': aMonths[nMonth],
      '%c': date.toUTCString(),
      '%C': Math.floor(nYear/100),
      '%d': zeroPad(nDate, 2),
      '%e': nDate,
      '%F': date.toISOString().slice(0,10),
      '%G': getThursday().getFullYear(),
      '%g': ('' + getThursday().getFullYear()).slice(2),
      '%H': zeroPad(nHour, 2),
      '%I': zeroPad((nHour+11)%12 + 1, 2),
      '%j': zeroPad(aDayCount[nMonth] + nDate + ((nMonth>1 && isLeapYear()) ? 1 : 0), 3),
      '%k': '' + nHour,
      '%l': (nHour+11)%12 + 1,
      '%m': zeroPad(nMonth + 1, 2),
      '%M': zeroPad(date.getMinutes(), 2),
      '%p': (nHour<12) ? 'AM' : 'PM',
      '%P': (nHour<12) ? 'am' : 'pm',
      '%s': Math.round(date.getTime()/1000),
      '%S': zeroPad(date.getSeconds(), 2),
      '%u': nDay || 7,
      '%V': (function() {
              var target = getThursday(),
                n1stThu = target.valueOf();
              target.setMonth(0, 1);
              var nJan1 = target.getDay();
              if (nJan1!==4) target.setMonth(0, 1 + ((4-nJan1)+7)%7);
              return zeroPad(1 + Math.ceil((n1stThu-target)/604800000), 2);
            })(),
      '%w': '' + nDay,
      '%x': date.toLocaleDateString(),
      '%X': date.toLocaleTimeString(),
      '%y': ('' + nYear).slice(2),
      '%Y': nYear,
      '%z': date.toTimeString().replace(/.+GMT([+-]\d+).+/, '$1'),
      '%Z': date.toTimeString().replace(/.+\((.+?)\)$/, '$1')
    }[sMatch] || sMatch;
  });
}

Sample usage:

strftime('%F'); // Returns "2016-09-15"
strftime('%A, %B %e, %Y'); // Returns "Thursday, September 15, 2016"

// You can optionally pass it a Date object...

strftime('%x %X', new Date('1/1/2016')); // Returns "1/1/2016 12:00:00 AM"

The latest code is available here: https://github.com/thdoan/strftime




Я сделал этот очень простой форматировщик, он обрезается / n / pastable (обновляется с опрятной версией):

function DateFmt(fstr) {
  this.formatString = fstr

  var mthNames = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
  var dayNames = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
  var zeroPad = function(number) {
     return ("0"+number).substr(-2,2);
  }

  var dateMarkers = {
    d:['getDate',function(v) { return zeroPad(v)}],
    m:['getMonth',function(v) { return zeroPad(v+1)}],
    n:['getMonth',function(v) { return mthNames[v]; }],
    w:['getDay',function(v) { return dayNames[v]; }],
    y:['getFullYear'],
    H:['getHours',function(v) { return zeroPad(v)}],
    M:['getMinutes',function(v) { return zeroPad(v)}],
    S:['getSeconds',function(v) { return zeroPad(v)}],
    i:['toISOString']
  };

  this.format = function(date) {
    var dateTxt = this.formatString.replace(/%(.)/g, function(m, p) {
      var rv = date[(dateMarkers[p])[0]]()

      if ( dateMarkers[p][1] != null ) rv = dateMarkers[p][1](rv)

      return rv

    });

    return dateTxt
  }

}

fmt = new DateFmt("%w %d:%n:%y - %H:%M:%S  %i")
v = fmt.format(new Date())

http://snipplr.com/view/66968.82825/




DateJS, безусловно, полнофункциональный, но я бы порекомендовал этот MUCH simpler lib (формат даты JavaScript), который я предпочитаю просто потому, что это всего лишь 120 строк или около того.




Related