Comments 37
отлично, спасибо!)
но я искал крохотный способ именно для описанной задачи.
но я искал крохотный способ именно для описанной задачи.
Как показывает практика, если начинается работа с датами — то каким-то конкретным случаем она не ограничивается.
Ну и тот же Momentjs не такой уж и огромный.
Ну и тот же Momentjs не такой уж и огромный.
за datejs не скажу, но momentjs тоже некорректно срабатывает в этом случае jsfiddle.net/yeaWn/1/
более того к написанию поста меня сподвигла именно особенность Safari
UFO just landed and posted this here
А не надежнее было сделать крохотный массив, а для февраля уж совсем не сложно посчитать.
Еще одна библиотека для работы с датами
arshaw.com/xdate/
arshaw.com/xdate/
тоже самое, смотрите сами: jsfiddle.net/rsboarder/RAupA/
Хочется сказать не про сам способ, а про то, как вы предлагаете его применять:
> Используя прекрассную возможность прототипирования в JavaScript можно расширить встроенный объект языка Date собственным методом
Это называется манки-патчинг (monkey patching) и лучше его избегать, потому что код, который вы напишете, рассчитывая на наличие этого патча, может быть использован где-то на стороне (не исключено что даже вами) и вместо желаемого результата, человек получит ошибку.
Уж лучше написать старую добрую простую функцию или если вам так нравится идея работать с классами, вы можете отнаследовать новый класс от стандартного Date, назвав его, например, ImprovedDate и работать с ним. Тогда, в его прототип вы сможете добавлять какие угодно методы и перекрывать любые стандартные уже объявленные.
> Используя прекрассную возможность прототипирования в JavaScript можно расширить встроенный объект языка Date собственным методом
Это называется манки-патчинг (monkey patching) и лучше его избегать, потому что код, который вы напишете, рассчитывая на наличие этого патча, может быть использован где-то на стороне (не исключено что даже вами) и вместо желаемого результата, человек получит ошибку.
Уж лучше написать старую добрую простую функцию или если вам так нравится идея работать с классами, вы можете отнаследовать новый класс от стандартного Date, назвав его, например, ImprovedDate и работать с ним. Тогда, в его прототип вы сможете добавлять какие угодно методы и перекрывать любые стандартные уже объявленные.
Monkey patching это будет называться в случае если daysInMonth уже определен в Date.
Нет большой разницы, изменять в ран-тайме уже существующие методы или добавлять новые. Вот, например, Википедия встает на мою сторону:
> A monkey patch is a way to extend or modify the run-time code of dynamic languages without altering the original source code.
Но я не о названии, а о том, что такой путь неправилен и применять его можно только для быстрой отладки в консоли, а для промышленных решений он не годится.
> A monkey patch is a way to extend or modify the run-time code of dynamic languages without altering the original source code.
Но я не о названии, а о том, что такой путь неправилен и применять его можно только для быстрой отладки в консоли, а для промышленных решений он не годится.
Как у тебя вообще с английским? Внимательно перечитай всю статью, а не первый попавшийся абзац. Там ни слова про «загрязнение» ранее объявленных классов-интерфейсов новыми методами, что является обычной практикой во всех динамических языках с наличием прототипов, модулей или traits, где код собирается по кускам
Может быть всему виной мое плохое знание английского или что-то другое, но я совершенно не могу понять почему добавление новых методов в прототип объекта не считается манки-патчингом и не попадает под определение: extend or modify the run-time code of dynamic languages.
И еще, я не могу понять откуда у взялось конкретное определение манки-патча как только изменение методов уже существующих классов-интерфейсов. Может быть виной всему то, что я вырываю куски из контекста и никогда не читаю ничего до конца, но вот я вырвал из статьи в вики кусок, в котором говорится «Monkey patching is used to… apply a patch at runtime to the objects in memory, instead of the source code on disk». Если я в прототипе Date объявлю дополнительное свойство, то оно появится у всех инстансов класса Date.
Никакого противоречия — действительно код выше модификацирует объекты в памяти, поэтому я не могу понять, почему добавление свойства или метода является манки-патчингом, а изменение — нет.
А еще, в принципе мне сложно понять, как можно считать вполне себе утилитарный класс Date можно считать классом-интерфейсом, но спишем это еще на какой-нибудь мой недостаток, может быть я вообще не разбираюсь в программировании.
Я изначально-то говорил не об этом. Мой комментарий был совершенно не про трактовку определений, а про то, что изменения прототипа стандартного класса «на лету» (как бы они ни назывались, манки-патчинг или «загрязнение» ранее объявленных классов-интерфейсов новыми методами) — плохая практика для JavaScript'а и лучше найти любой другой способ, недостатка в которых нет.
И еще, я не могу понять откуда у взялось конкретное определение манки-патча как только изменение методов уже существующих классов-интерфейсов. Может быть виной всему то, что я вырываю куски из контекста и никогда не читаю ничего до конца, но вот я вырвал из статьи в вики кусок, в котором говорится «Monkey patching is used to… apply a patch at runtime to the objects in memory, instead of the source code on disk». Если я в прототипе Date объявлю дополнительное свойство, то оно появится у всех инстансов класса Date.
var myDate = new Date();
Date.prototype.isMonkeyPatched = true;
myDate.isMonkeyPatched; // true
Никакого противоречия — действительно код выше модификацирует объекты в памяти, поэтому я не могу понять, почему добавление свойства или метода является манки-патчингом, а изменение — нет.
А еще, в принципе мне сложно понять, как можно считать вполне себе утилитарный класс Date можно считать классом-интерфейсом, но спишем это еще на какой-нибудь мой недостаток, может быть я вообще не разбираюсь в программировании.
Я изначально-то говорил не об этом. Мой комментарий был совершенно не про трактовку определений, а про то, что изменения прототипа стандартного класса «на лету» (как бы они ни назывались, манки-патчинг или «загрязнение» ранее объявленных классов-интерфейсов новыми методами) — плохая практика для JavaScript'а и лучше найти любой другой способ, недостатка в которых нет.
// monkey patching valueOf
Date.prototype.oldValueOf = Date.prototype.valueOf
Date.prototype.valueOf = function() {
return parseInt(this.oldValueOf() / 1000);
}
vs
// extending Date
Date.prototype.valueOfInSeconds = function() {
return parseInt(this.valueOf() / 1000);
}
Заметно разницу? Первый пример — классический манки-патч, влияющий на остальной код, который использует Date#valueOf. Второй пример — динамическое расширение прототипа Date _новым_ методом, которое никоим образом не влияет на остальные инстансы Date (поменялся прототип, а не поведение ранее объявленных методов).
Date.prototype.oldValueOf = Date.prototype.valueOf
Date.prototype.valueOf = function() {
return parseInt(this.oldValueOf() / 1000);
}
vs
// extending Date
Date.prototype.valueOfInSeconds = function() {
return parseInt(this.valueOf() / 1000);
}
Заметно разницу? Первый пример — классический манки-патч, влияющий на остальной код, который использует Date#valueOf. Второй пример — динамическое расширение прототипа Date _новым_ методом, которое никоим образом не влияет на остальные инстансы Date (поменялся прототип, а не поведение ранее объявленных методов).
А вот пример изменения в «рантайме» (то, что как раз имелось ввиду в статье):
var date = new Date()
date.valueOf() // 1366289455443
date.valueOf = function() {
return 1;
}
date.valueOf() // 1
var date = new Date()
date.valueOf() // 1366289455443
date.valueOf = function() {
return 1;
}
date.valueOf() // 1
Раз такой хороший тред тут образовался — может, кто-нибудь знает библиотеку для работы с датами, которая умеет прибавлять к дате N рабочих дней? А то сейчас приходится использовать самописный костыль (и он меня немного пугает):
// add numDays to oldDate and return resulting date
function add_days(oldDate, numDays) {
var new_date = new Date(oldDate.getFullYear(),oldDate.getMonth(),oldDate.getDate()+parseInt(numDays));
return new_date;
}
function add_working_days(to_date, days) {
// to_date: starting date,
// days = number of working days to add
var temp_date = new Date();
var i = 0;
var days_to_add = 0;
while (i < (days)){
temp_date = add_days(to_date, days_to_add);
//0 = Sunday, 6 = Saturday, if the date not equals a weekend day then increase by 1
if ((temp_date.getDay() != 0) && (temp_date.getDay() != 6)) {
i+=1;
}
days_to_add += 1;
}
return add_days(to_date, days_to_add);
}
Вполне нормальное решение, имхо.
Если, правда, вам не нужно проверять по производственному календарю праздники.
Если, правда, вам не нужно проверять по производственному календарю праздники.
О, вот как называется календарь с нерабочими днями, спасибо за наводку :)
Например:
или компактная версия:
Возможно требует корректировок.
function getDaysByWD(dayOfWeek, num) {
// на каждые 5 рабочих дней - полная неделя
var full = parseInt(num / 5) * 7;
// считаем остаток
var rest = num % 5;
// корректировка по выходным, пока ноль
var d = 0;
// Если суббота - то один день
if (dayOfWeek == 6) {
d = 1;
}
// а для рабочих дней
else if (dayOfWeek > 0) {
// считаем сколько дней осталось до выходных
daysToWeeknd = 6 - dayOfWeek - 1;
// если в остатке больше, чем до выходных
// то нужно посчитать ещё одну пару выходных
if (rest > daysToWeeknd) {
d = 2;
}
}
return full + rest + d;
}
или компактная версия:
function getDaysByWD(w,n,r) {
return parseInt(n/5)*7+(r=n%5)+(w>0?w<6?r>(5-w)?2:0:1:0);
}
Возможно требует корректировок.
Если не ошибаюсь, в вашем алгоритме есть ошибка: если к пятнице прибавить один рабочий день, то вернётся суббота. Логичней было бы вернуть понедельник.
А так разве не проще?
var first = new Date(2011, 3, 1).getTime(),
second = new Date(2011, 4, 1).getTime();
console.log((second - first)/86400000);
В JS хорошо поддержана работа с датами — просто не надо выходить за пределы документированности. Никто не гарантирует, что
Как сосчитать число дней в месяце? Берём время первого числа следующего месяца, вычитаем время 1 числа текущего, делим на число микросекунд в сутках.
Тут можно сократить. Но суть в том, что так совершенно без трюков (не считая +new вместо getTime()) берётся число дней, пользуясь работой с датами.
А Вы в выводах написали 2 противоречащих утверждения: «Идеальная практика» и «Данный способ работает в Safari пока также хорошо». Способ, «работающий, пока», не может быть идеальным: ).
new Date(Y, M, 33)
будет работать.Как сосчитать число дней в месяце? Берём время первого числа следующего месяца, вычитаем время 1 числа текущего, делим на число микросекунд в сутках.
var d = +new Date()
, thYear = d.getFullYear(), thMonth = d.getMonth()
, nextMonth = (thMonth +1) % 12, nextYear = thYear + (thMonth==11);
var daysInThMonth = (+new Date(nextYear, nextMonth, 1) - new Date(thYear, thMonth, 1))/ 86400000;
Тут можно сократить. Но суть в том, что так совершенно без трюков (не считая +new вместо getTime()) берётся число дней, пользуясь работой с датами.
А Вы в выводах написали 2 противоречащих утверждения: «Идеальная практика» и «Данный способ работает в Safari пока также хорошо». Способ, «работающий, пока», не может быть идеальным: ).
я вот такое использую:
var _date:Date = new Date(year, month+1, 1);
_date.date--;
trace(_date.date);
var _date:Date = new Date(year, month+1, 1);
_date.date--;
trace(_date.date);
Спасибо за статью. Очень помогли. Ранее расчет вел с помощью другого алгоритма, который имеет в себе ряд изъянов.
Sign up to leave a comment.
Даты в JavaScript: количество дней в месяце и некоторые особенности Safari