简体   繁体   English

Java-以日期格式交换月份和日期

[英]Java - Swap Month & Day in Date Format

I have a String date format (eg dd/MM/yyyy) and want to convert it to a US-style with the month first (eg MM/dd/yyyy), programatically. 我有一个String日期格式(例如dd / MM / yyyy),并希望以编程方式将其转换为美国格式,并以月份开头(例如MM / dd / yyyy)。

The use-case of this is to read some data and determine which format fits best. 这种情况的用例是读取一些数据并确定哪种格式最合适。

This sounds trivially easy, but having actually tried implementing it, my solution seems sub-optimal. 这听起来很简单,但是实际上尝试实现它之后,我的解决方案似乎不是最优的。

Below is my attempt, including a test. 以下是我的尝试,包括测试。

public class DateSwapperExample
{
    private static final char dateFormatDayLetter = 'd', dateFormatMonthLetter = 'M';

    /**
     * Swaps the Day & Month component in a Date Format, if both are present <br>
     * When swapping, ensures the frequency is retained - e.g. dd/MMM -> MMM/dd <br>
     * TODO Only handles one instance of each tag <br>
     * TODO This doesn't handle quoted elements in the Date Format (e.g. "dd/mm 'since dave made the best cakes' yyyy")
     */
    private static String swapDayAndMonthInDateFormat(final String dateFormat)
    {
        // Get the position of the groups
        final int[] dayIndex = new int[] {dateFormat.indexOf(dateFormatDayLetter), dateFormat.lastIndexOf(dateFormatDayLetter)};
        final int[] monthIndex = new int[] {dateFormat.indexOf(dateFormatMonthLetter), dateFormat.lastIndexOf(dateFormatMonthLetter)};

        if ((dayIndex[0] == -1) || (monthIndex[0] == -1))
        {
            // Cannot swap as dateFormat does not contain both dateFormatDayLetter & dateFormatMonthLetter
            return dateFormat;
        }
        else
        {
            final int[] firstGroup, secondGroup;

            // Work out which group comes first
            if (dayIndex[0] < monthIndex[0])
            {
                firstGroup = dayIndex;
                secondGroup = monthIndex;
            }
            else
            {

                firstGroup = monthIndex;
                secondGroup = dayIndex;
            }

            // Split the string up into segments, re-organise and combine

            // The other parts of the format at the start
            return substringConstrained(dateFormat, 0, firstGroup[0])
                    // The second group
                    + substringConstrained(dateFormat, secondGroup[0], secondGroup[1] + 1)
                    // The other parts of the format in the middle
                    + substringConstrained(dateFormat, firstGroup[1] + 1, secondGroup[0])
                    // The first group
                    + substringConstrained(dateFormat, firstGroup[0], firstGroup[1] + 1)
                    // The other parts of the format at the end
                    + substringConstrained(dateFormat, secondGroup[1] + 1, dateFormat.length());
        }
    }

    /** Extension of {@link String#substring(int, int)} that constrains the index parameters to be within the allowed range */
    private static String substringConstrained(final String str, final int beginIndex, final int endIndex)
    {
        return str.substring(constrainToRange(beginIndex, 0, str.length()), constrainToRange(endIndex, 0, str.length()));
    }

    /** Copy of {@link com.google.common.primitives.Ints#constrainToRange(int, int, int)} to avoid the need of Guava in this example */
    private static int constrainToRange(int value, int min, int max)
    {
        return Math.min(Math.max(value, min), max);
    }

    @org.junit.Test
    public void testSwapDayAndMonthInDateFormat()
    {
        org.junit.Assert.assertEquals("Md", swapDayAndMonthInDateFormat("dM"));
        org.junit.Assert.assertEquals("MMd", swapDayAndMonthInDateFormat("dMM"));
        org.junit.Assert.assertEquals("Mdy", swapDayAndMonthInDateFormat("dMy"));
        org.junit.Assert.assertEquals("Myd", swapDayAndMonthInDateFormat("dyM"));
        org.junit.Assert.assertEquals("yMd", swapDayAndMonthInDateFormat("ydM"));
        org.junit.Assert.assertEquals("aMbdc", swapDayAndMonthInDateFormat("adbMc"));
        org.junit.Assert.assertEquals("MM/dd/yyyy", swapDayAndMonthInDateFormat("dd/MM/yyyy"));
        org.junit.Assert.assertEquals("MMM/dd/yyyy", swapDayAndMonthInDateFormat("dd/MMM/yyyy"));

        for (final String str : new String[] {"ydy", "yMy", "yDy", "ymy", "Dm", "Dmm", "DD/mm/yyyy", "DD/mmm/yyyy"})
        {
            org.junit.Assert.assertEquals(str, swapDayAndMonthInDateFormat(str));
        }
    }
}
private static String swapDayAndMonthInDateFormat(final String dateFormat)
{
    return dateFormat.replaceFirst("(d+)(.*?)(M+)", "$3$2$1");
}

I am far from convinced that this is the good solution to your real problem. 我远不能相信这是解决您实际问题的好方法。 But it makes you test pass. 但这使您通过测试。

Also you should not want to use SimpleDateFormat . 另外,您不应该使用SimpleDateFormat That class is notoriously troublesome and along with Date and friends long outdated. 那个班级出了名的麻烦,而且Date和朋友早已过时了。 Instead use DateTimeFormatter and other classes from java.time, the modern Java date and time API. 而是使用DateTimeFormatter和来自Java.time(现代Java日期和时间API)中的其他类。 Format pattern strings still look similar, though, so it could be that this answer is still relevant. 不过,格式模式字符串看起来仍然很相似,因此可能答案仍然很重要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM