从格里高利转换为儒略历

时间:2017-10-24 09:00:07

标签: java calendar gregorian-calendar

我需要创建一个程序,从.csv文件中读取日期并对其进行转换,以便添加13天。我已经这样做但不知何故它没有按照希望添加以下日期。它也超过30天,例如2001-12-42不应该发生。

public static void main(String[] args) throws FileNotFoundException, ParseException {
    File fread = new File("src/daten-greg.csv");
    File fwrite = new File("src/daten-jul.csv");

    Scanner s = new Scanner(fread);
    PrintStream print = new PrintStream(fwrite);

    while(s.hasNext()) {
        String[] line = s.nextLine().split(" ");
        print.println(String.join(" ", Convert(line)));
    }

    s.close();
    print.close();
}

private static String[] Convert(String[] value) throws ParseException {
    for (int i = 0; i < value.length; i+=1)
        value[i] = ToJulianisch(value[i]);

    return value;
}

private static String ToJulianisch(String date) throws ParseException {
    SimpleDateFormat  sdf = new SimpleDateFormat("yyyy-mm-dd");
    Date d = sdf.parse(date);


    Calendar c = Calendar.getInstance();
    c.setTime(d);

    int actDay = c.get(Calendar.DAY_OF_MONTH);
    int actMonth = c.get(Calendar.MONTH) + 1 ;
    int actYear = c.get(Calendar.YEAR);
    actDay -= 13;

    if(actDay - 13 < 1) {
        actMonth -= 1;
        if(actMonth < 1) {
            actMonth = 12;
            actYear -= 1;
        }   
        Calendar k = Calendar.getInstance();
        k.set(Calendar.YEAR, actYear);
        k.set(Calendar.MONTH, actMonth - 1);
        actDay = k.getActualMaximum(Calendar.DAY_OF_MONTH) + actDay;
    }

    return String.format("%s-%s-%s", actYear, actMonth, actDay);
}

2 个答案:

答案 0 :(得分:3)

您要从actDay两次减去13,先是actDay-=13,另一次是if(actDay - 13 < 1)。在if块内,然后将小于14的值添加到每月的天数中,从而导致月中溢出。

如果您只想从给定日期减去13天,则应使用c.set(Calendar.DAY_OF_MONTH,actDay-13)。这将在Calendar对象内正确处理减法,然后您可以使用

actDay = c.get(Calendar.DAY_OF_MONTH);
int actMonth = c.get(Calendar.MONTH) + 1 ;
int actYear = c.get(Calendar.YEAR);
return String.format("%s-%s-%s", actYear, actMonth, actDay);

答案 1 :(得分:2)

关于算法中的一些错误,请参阅HeikkiMäenpää的答案。我还看到了另一个错误,即错误的模式“yyyy-mm-dd”,其中“mm”代表分钟(使用“MM”几个月)。

但总的来说,你似乎试图重新发明轮子。即使旧的java.util.Calendar - API也有从gregorian到julian日历日期转换的内置方式,请参阅我的解决方案,该解决方案即使在过去的任何日期也适用于切换。

您的解决方案仅适用于格里高利和朱利安历法之间的距离为13天的日期(过去不是这样,在教皇格雷戈尔改革时,只有10天被切断)。

public static void main(String[] args) throws ParseException {
  String input = "2017-10-24";
  System.out.println("Old API => " + toJulianisch(input)); // 2017-10-11
}

private static String toJulianisch(String date) throws ParseException {
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
  GregorianCalendar gcal = new GregorianCalendar();
  gcal.setTimeZone(TimeZone.getTimeZone("GMT"));
  gcal.setGregorianChange(new Date(Long.MIN_VALUE));
  sdf.setCalendar(gcal);
  Date d = sdf.parse(date);

  gcal.setGregorianChange(new Date(Long.MAX_VALUE));
  gcal.setTime(d);
  return sdf.format(d);
}

正如您所看到的,旧的API函数甚至会强制您将时区设置为固定的偏移量,以避免任何可能的时区混乱。这是必要的,因为java.util.Calendarjava.util.Date不是真正的日历日期,而是瞬间/时刻。

旁注:

我写了一个时间库(Time4J),如果它是格里高利或朱利安(甚至是瑞典语),它甚至可以处理任何historic date平等,在历史性年份开始时相等(在大多数情况下)不是一月的第一天!)等。也许这对你的问题来说太过分了,但我提到了你真正希望以真实的历史日历日期运作的情况。