В настоящее время я разрабатываю некоторые функции, которые должны либо вычесть, либо добавить время к экземпляру класса Calendar. Время, когда мне нужно добавить / sub, находится в файле свойств и может быть любым из этих форматов:
30,sec
90,sec
1.5,min
2,day
2.333,day
Предположим дополнение для простоты. Я бы прочитал эти значения в массиве String:
String[] propertyValues = "30,sec".split(",");
Я бы прочитал второе значение в этой паре, разделенной запятыми, и сопоставил бы его с соответствующим int в классе Calendar (так, например, «sec» становится Calendar.SECOND, «min» становится Calendar.MINUTE):
int calendarMajorModifier = mapToCalendarClassIntValues(propertyValues[1]);
Чтобы затем выполнить фактическую операцию, я бы сделал это так же просто, как:
cal.add(calendarMajorModifier, Integer.parseInt(propertyValues[0]));
Это работает, и это не слишком сложно. Теперь проблема заключается в плавающих значениях (например, 2.333, день для eaxmple) - как бы вы с этим справились?
String[] propertyValues = "2.333,day".split(",");
Как вы понимаете, код становится довольно сложным (на самом деле я его еще не написал, поэтому не обращайте внимания на синтаксические ошибки)
float timeComponent = Float.parseFloat(propertyValues[0]);
if (calendarMajorModifier == Calendar.DATE) {
int dayValue = Integer.parseFloat(timeComponent);
cal.add(calendarMajorModifier, dayValue);
timeComponent = (timeComponent - dayValue) * 24; //Need to convert a fraction of a day to hours
if (timeComponent != 0) {
calendarMajorModifier = Calendar.HOUR;
}
}
if (calendarMajorModifier == Calendar.HOUR) {
int hourValue = Integer.parseFloat(timeComponent);
cal.add(calendarMajorModifier, hourValue);
timeComponent = (timeComponent - hourValue) * 60; //Need to convert a fraction of an hour to minutes
if (timeComponent != 0) {
calendarMajorModifier = Calendar.MINUTE;
}
}
... etc
Конечно, я понимаю, что может быть возможность рефакторинга, но все же кажется очень грубым решением.
Я использую класс Calendar для выполнения операций, но технически это может быть любой класс. Пока я могу конвертировать между ними (т.е. получая длинное значение и используя его), так как функция потребности возвращает класс Calendar. В идеале класс также должен быть родным для Java, чтобы избежать проблем с лицензированием третьих лиц :).
Боковое примечание: я предложил изменить формат на что-то вроде yy: MM: ww: dd: hh: mm: ss, чтобы избежать плавающих значений, но это не сработало. Я также предложил что-то вроде 2, дня, 5, часа, но опять же, в идеале это должно быть указано выше.
Это может быть List<Adjustment>, и каждый из них применяется к cal (или какому-либо другому типу объекта). Запись свойства 2,day имеет только 1 элемент в списке, в то время как 2.333,day имеет два элемента в списке. И отделите синтаксический анализ значения свойства от применения корректировок.
Вам нужно будет кодировать переходы самостоятельно (хотя подумайте о рабочей библиотеке java.time вместо календаря) - на самом деле нет «дроби» ни в одной из наших единиц времени - когда мы говорим «полтора дня», что на самом деле мы имеем в виду «1 день, 12 часов». Это преобразование обычно не представлено какой-либо библиотекой datetime из-за того, насколько оно на самом деле произвольно.
Я посмотрю на класс Time и посмотрю, поможет ли это упростить задачу - в конце концов, на выходе все равно должен быть класс Calendar, независимо от того, что устарело или нет. И действительно, Прохоров, формат мне тоже не очень нравится, так как вы наталкиваетесь на эти глупые подсчеты, к сожалению, окончательного решения у меня нет :)
@Martin, по сути, вы отделяете целую часть от имеющейся у вас единицы. Затем вы берете следующую наименьшую единицу и целую часть этой единицы и так далее (вам также нужно будет создать здесь упорядоченную структуру единиц). В результате этого анализа вы должны получить от 2.333 days что-то точно близкое к 2 days 7 hours 59 minutes 31 seconds 2 centiseconds (учитывая, что входной сигнал - 2.333, а это не точная треть дня). Чтобы сделать это менее строгим, вы можете, например, округлить минуты до часов, если вы получили ввод в днях и т. д.
В идеале вы могли бы позволить своим пользователям вводить периоды времени с таким количеством полей, которое им необходимо, чтобы значения всех полей были целыми числами. Но я полагаю, что это исключено.




Я бы преобразовал значение в наименьшую единицу и добавил:
float timeComponent = Float.parseFloat(propertyValues[0]);
int unitFactor = mapUnitToFactor(propertyValues[1]);
cal.add(Calendar.SECOND, (int)(timeComponent * unitFactor));
а mapUnitToFactor будет примерно таким:
int mapUnitToFactor(String unit)
{
if ("sec".equals(unit))
return 1;
if ("min".equals(unit))
return 60;
if ("hour".equals(unit))
return 3600;
if ("day".equals(unit))
return 24*3600;
throw new InvalidParameterException("Unknown unit: " + unit);
}
Так, например, 2,333 дня превратятся в 201571 секунду.
Спасибо за ответ. Я действительно рассматривал аналогичную функцию, поскольку она относительно чистая, и наполовину реализовывала ее, пока не заговорили о том, что также имеет значение «1, месяц» в качестве допустимого значения свойства, что, к сожалению, разрушит эту реализацию. Но я могу убедить их, что плавающие значения для месяца трудно вычислить, и поэтому разрешены только целочисленные значения для месяца.
Не в каждом дне 86400 секунд. Чтобы максимально точно соответствовать источнику, лучше всего делать точки как можно более грубыми.
@Martin Ага, месяц с плавающей запятой не имеет смысла. Чтобы реализовать это (независимо от того, как), вам нужно будет указать фиксированный размер для интерпретации доли месяца. Но это просто катастрофа, ожидающая своего часа. И, как указал @MProkhorov, это верно даже в течение нескольких дней (и, следовательно, недель), хотя в зависимости от того, насколько точным вы хотите, чтобы это было, дополнительная секунда может быть не такой большой проблемой (иначе вы не должны в любом случае используя поплавки).
Я предлагаю вам использовать Java Time API.
Calendarустарел. Кроме того, чтобы иметь дело с десятичными значениями произвольной точности, я предлагаю взглянуть на классBigDecimal.