当前位置: 首页 > 知识库问答 >
问题:

使用java基于区域设置从一周的第一天开始打印日历。时间/Java-8

徐飞龙
2023-03-14

我看到的所有日历视图库和基于日历的日期选择器的示例都使用旧的日历API。然而,我还没有找到任何使用Java8日期API构建日历视图的方法。这是我试图实现的目标,基本上已经做到了,但我遇到的问题是使用区域设置设置一周的第一天。

我已经设法获取并显示了给定月份一周中每一天的所有日期。但是,我遇到的问题是生成的日历不会从基于我的语言环境的一周的第一天开始。Java. Time使用的DayOfWeekenum开始计算从周一到周日(1-7)的天数。但是,我希望日历按语言环境显示天数,在我的情况下,是周日到周六。

根据文档,WeekFields类提供了对基于区域设置的一周中的几天的访问,并具有“正确”的值,但我不确定如何正确使用它。

这是我迄今为止所做的:

private enum class DaysOfWeek {
    SUNDAY,
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY
}

fun TimetableCalendar() {
    val dates = getDaysOfMonth(LocalDate.now().year, LocalDate.now().month)
    
    // WORK AROUND: Hardcoding the first day of the week by manually inserting them into a new map
    val tempDates = hashMapOf<DaysOfWeek, MutableList<LocalDate>>()
    tempDates[DaysOfWeek.SUNDAY] = dates[DayOfWeek.SUNDAY] !!
    tempDates[DaysOfWeek.MONDAY] = dates[DayOfWeek.MONDAY] !!
    tempDates[DaysOfWeek.TUESDAY] = dates[DayOfWeek.TUESDAY] !!
    tempDates[DaysOfWeek.WEDNESDAY] = dates[DayOfWeek.WEDNESDAY] !!
    tempDates[DaysOfWeek.THURSDAY] = dates[DayOfWeek.THURSDAY] !!
    tempDates[DaysOfWeek.FRIDAY] = dates[DayOfWeek.FRIDAY] !!
    tempDates[DaysOfWeek.SATURDAY] = dates[DayOfWeek.SATURDAY] !!

    // Sort the days by ordinal, 0 - 6
    val sortedDates = tempDates.toSortedMap(compareBy {
        d -> d.ordinal
    })

    LazyVerticalGrid(
        cells = GridCells.Fixed(7),
        contentPadding = PaddingValues(16. dp)
    ) {
        // Display short day of week name
        items(sortedDates.keys.toList()) { dayOfWeek ->
                Text(text = dayOfWeek.name.substring(0, 3), textAlign = TextAlign.Center)
        }
        itemsIndexed(sortedDates.values.toList()) { _, date ->
            Column(
                modifier = Modifier.padding(4. dp)
            ) {
                date.forEach { day ->
                        DateView(date = day.dayOfMonth.toString())
                }
            }
        }
    }
}

/**
 * Returns the dates for each day of the week in the given [year] and [month]
 * Including dates of the previous and next month if the [month] does not
 * begin on the first or last day of the week
 */
fun getDaysOfMonth(year: Int, month: Month): HashMap<DayOfWeek, MutableList<LocalDate>> {
    val weekFields = WeekFields.of(Locale.getDefault())

    val daysOfWeek = mutableSetOf<DayOfWeek>()
    daysOfWeek.add(DayOfWeek.SUNDAY)
    daysOfWeek.add(DayOfWeek.MONDAY)
    daysOfWeek.add(DayOfWeek.TUESDAY)
    daysOfWeek.add(DayOfWeek.WEDNESDAY)
    daysOfWeek.add(DayOfWeek.THURSDAY)
    daysOfWeek.add(DayOfWeek.FRIDAY)
    daysOfWeek.add(DayOfWeek.SATURDAY)

    val ym = YearMonth.of(year, month)
    val firstOfMonth = ym.atDay(1) // first day of the month
    val lastDayOfMonth = ym.atDay(ym.lengthOfMonth())

    val dayDates = hashMapOf<DayOfWeek, MutableList<LocalDate>>()

    // Get all the dates for each day of the week
    daysOfWeek.forEach { day ->
            val dates = mutableListOf<LocalDate>()
        var ld = firstOfMonth.with(TemporalAdjusters.dayOfWeekInMonth(1, day))
        do {
            dates.add(ld)
            ld = ld.plusWeeks(1)
        } while (YearMonth.from(ld).equals(ym))
        dayDates[day] = dates
    }

    // If current month does not start on a Sunday, get the last few days of the previous month
    if (firstOfMonth.dayOfWeek != weekFields.firstDayOfWeek) {
        val previousMonth = YearMonth.of(year, month.minus(1))
        var lastDateOfPrevMonth = LocalDate.of(year, previousMonth.month, previousMonth.atEndOfMonth().dayOfMonth)

        do {
            dayDates[lastDateOfPrevMonth.dayOfWeek]?.add(0, lastDateOfPrevMonth)
            lastDateOfPrevMonth = lastDateOfPrevMonth.minusDays(1)
        } while (lastDateOfPrevMonth.dayOfWeek != DayOfWeek.SATURDAY)
    }

    // If current month does not end on a saturday, get the first few days of the next month
    if (lastDayOfMonth.dayOfWeek != weekFields.firstDayOfWeek.minus(1)) {
        val nextMonth = YearMonth.of(year, month.plus(1))
        var firstDateOfNextMonth = LocalDate.of(year, nextMonth.month, 1)

        do {
            dayDates[firstDateOfNextMonth.dayOfWeek]?.add(firstDateOfNextMonth)
            firstDateOfNextMonth = firstDateOfNextMonth.plusDays(1)
        } while (firstDateOfNextMonth.dayOfWeek != DayOfWeek.SUNDAY)
    }

    return dayDates
}

上述代码按预期工作,并显示从周日开始的一周日历。像我所做的那样,使用从周日开始的新枚举,手动将一周中的几天插入到一个新的hashmap中,有意义吗?或者让date api来处理(如果可能的话)以及如何处理会更有意义吗?

还是我只是采取了错误的方法,日历API会是更好的选择?

共有3个答案

沈博达
2023-03-14

使用java非常简单。时间,现代日期时间API。第一步是根据你的语言环境找到一周中的第一天,你可以按如下操作:

DayOfWeek firstDayOfWeek = WeekFields.of(locale).getFirstDayOfWeek();
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        // Let's test it
        System.out.println(getWeekDays(Locale.UK));
        System.out.println(getWeekDays(Locale.US));
    }

    static List<DayOfWeek> getWeekDays(Locale locale) {
        LocalDate localDate = LocalDate.now();

        // First day of week
        DayOfWeek firstDayOfWeek = WeekFields.of(locale).getFirstDayOfWeek();

        LocalDate date = localDate.with(TemporalAdjusters.dayOfWeekInMonth(0, firstDayOfWeek));
        return IntStream.rangeClosed(0, 6)
                    .mapToObj(i -> date.plusDays(i).getDayOfWeek())
                    .collect(Collectors.toList());
    }
}

输出:

[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]
[SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY]

在线演示

其余的逻辑围绕着创建具有适当行间距的标签,任何人都应该能够使用循环的基本知识来做这件事。

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.Locale;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        // Let's test it
        System.out.println(getMonthCalendar(Locale.UK));
        System.out.println("-+-+-+-+-+-+-+-+-+-+-+-+-+-");
        System.out.println(getMonthCalendar(Locale.US));
    }

    static String getMonthCalendar(Locale locale) {
        LocalDate localDate = LocalDate.now();
        YearMonth ym = YearMonth.of(localDate.getYear(), localDate.getMonthValue());
        StringBuilder sb = new StringBuilder();

        // First day of week
        DayOfWeek firstDayOfWeek = WeekFields.of(locale).getFirstDayOfWeek();

        LocalDate date = localDate.with(TemporalAdjusters.dayOfWeekInMonth(0, firstDayOfWeek));
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE", locale);
        sb.append(
                    IntStream.rangeClosed(0, 6)
                    .mapToObj(i -> dtf.format(date.plusDays(i)))
                    .collect(Collectors.joining(" "))
        )
        .append(System.lineSeparator());

        int counter = 1;

        // Print as many space as the difference between the day of week of 1st date of
        // the month and the first day of the week in that Locale
        int dayValue = localDate.withDayOfMonth(1).getDayOfWeek().getValue() - firstDayOfWeek.getValue();
        dayValue = dayValue < 0 ? 7 + dayValue : dayValue;
        for (int i = 0; i < dayValue; i++, counter++) {
            sb.append(String.format("%-4s", ""));
        }

        for (int i = 1; i <= ym.getMonth().length(ym.isLeapYear()); i++, counter++) {
            sb.append(String.format("%-4d", i));

            // Break the line if the value of the counter is multiple of 7
            if (counter % 7 == 0) {
                sb.append(System.lineSeparator());
            }
        }

        return sb.toString();
    }
}

输出:

Mon Tue Wed Thu Fri Sat Sun
        1   2   3   4   5   
6   7   8   9   10  11  12  
13  14  15  16  17  18  19  
20  21  22  23  24  25  26  
27  28  29  30  
-+-+-+-+-+-+-+-+-+-+-+-+-+-
Sun Mon Tue Wed Thu Fri Sat
            1   2   3   4   
5   6   7   8   9   10  11  
12  13  14  15  16  17  18  
19  20  21  22  23  24  25  
26  27  28  29  30  

在线演示

查看英国日历和美国日历进行比较。

从Trail:Date-Time了解更多有关现代日期时间API的信息。

*由于任何原因,如果您必须坚持Java6或Java7,您可以使用ThreeTen-Backport,它将大部分java.time功能反向移植到Java6

雍河
2023-03-14

无需定义私有枚举类DaysOfWeek{…}。请参见DayOfWeek

了解如何获取特定地区/国家的每周第一天。

DayOfWeek firstDayOfWeek = WeekFields.of( Locale.CANADA_FRENCH ).getFirstDayOfWeek();

使用YearMonth来表示年份和月份。

ZoneId z = ZoneId.of( "America/Montreal" ) ;
YearMonth yearMonth = YearMonth.now( z ) ;

得到当月的第一天。

LocalDate firstOfMonth = yearMonth.atDay( 1 ) ;

如果需要,及时后退以找到一周的第一天。使用TemporalAduster实现。

TemporalAdjuster ta = TemporalAdjusters.previousOrSame( firstDayOfWeek ) ;
LocalDate startOfCalendar = firstOfMonth.with( ta );

构建我们的日历。使用可导航的地图将每个星期的数字收集到LocalDate对象的列表中。

NavigableMap< Integer , List< LocalDate > > calendar = new TreeMap<>() ;

或者只是使用一个列表。

List< List < LocalDate > > calendar = new ArrayList<>() ;

做一周。

LocalDate ld = startOfCalendar ; 
List< LocalDate > week = ld.datesUntil( ld.plusWeeks(1) ).toList() ;

如果使用较旧版本的Java,请替换该。datesUntil使用自己的循环行。

int daysInWeek = 7;
List < LocalDate > week = new ArrayList <>( daysInWeek );
for ( int indexIntoWeek = 0 ; indexIntoWeek < daysInWeek ; indexIntoWeek++ )
{
    week.add( ld.plusDays( indexIntoWeek ) );
}

将那一周添加到您的地图中,并继续直到进入新的YearMonth

把所有的代码放在一起。

// Populate data.
DayOfWeek firstDayOfWeek = WeekFields.of( Locale.CANADA_FRENCH ).getFirstDayOfWeek();

ZoneId z = ZoneId.of( "America/Montreal" );
YearMonth yearMonth = YearMonth.now( z );
LocalDate firstOfMonth = yearMonth.atDay( 1 );

TemporalAdjuster ta = TemporalAdjusters.previousOrSame( firstDayOfWeek );
LocalDate startOfCalendar = firstOfMonth.with( ta );

NavigableMap < Integer, List < LocalDate > > calendar = new TreeMap <>();
int nthWeek = 1;
LocalDate ld = startOfCalendar;
while ( ! YearMonth.from( ld ).isAfter( yearMonth ) )
{
    List < LocalDate > week = ld.datesUntil( ld.plusWeeks( 1 ) ).toList();
    calendar.put( nthWeek++ , week );
    ld = ld.plusWeeks( 1 );  // Set up the next loop. Increment `ld` to the next week.
}

// Report results.
for ( Integer weekNumber : calendar.keySet() )
{
    DateTimeFormatter f = DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).withLocale( Locale.US );
    System.out.println( "weekNumber = " + weekNumber );
    for ( LocalDate localDate : calendar.get( weekNumber ) )
    {
        String output = localDate.getDayOfWeek().getDisplayName( TextStyle.FULL , Locale.US ) + " = " + localDate.format( f );
        System.out.println( output );
    }
}

跑步的时候。

weekNumber = 1
Sunday = 8/29/21
Monday = 8/30/21
Tuesday = 8/31/21
Wednesday = 9/1/21
Thursday = 9/2/21
Friday = 9/3/21
Saturday = 9/4/21
weekNumber = 2
Sunday = 9/5/21
Monday = 9/6/21
Tuesday = 9/7/21
Wednesday = 9/8/21
Thursday = 9/9/21
Friday = 9/10/21
Saturday = 9/11/21
weekNumber = 3
Sunday = 9/12/21
Monday = 9/13/21
Tuesday = 9/14/21
Wednesday = 9/15/21
Thursday = 9/16/21
Friday = 9/17/21
Saturday = 9/18/21
weekNumber = 4
Sunday = 9/19/21
Monday = 9/20/21
Tuesday = 9/21/21
Wednesday = 9/22/21
Thursday = 9/23/21
Friday = 9/24/21
Saturday = 9/25/21
weekNumber = 5
Sunday = 9/26/21
Monday = 9/27/21
Tuesday = 9/28/21
Wednesday = 9/29/21
Thursday = 9/30/21
Friday = 10/1/21
Saturday = 10/2/21
空慈
2023-03-14

您完全正确:要正确地对语言环境中的星期几进行排序,也就是说,根据该语言环境,星期几是一周的第一天,您需要使用适当的WeekFields对象。以下Java方法只是一个简短的演示:

public static void sortAndPrintDaysOfWeek(Locale loc) {
    List<DayOfWeek> daysOfTheWeek = Arrays.asList(DayOfWeek.values());
    WeekFields wf = WeekFields.of(loc);

    daysOfTheWeek.sort(Comparator.comparingInt(dow -> dow.get(wf.dayOfWeek())));

    System.out.println(daysOfTheWeek);
}

我相信你会对你的Kotlin排序地图应用类似的比较器。尝试上述方法:

    sortAndPrintDaysOfWeek(Locale.FRANCE);

输出:

[周一、周二、周三、周四、周五、周六、周日]

    sortAndPrintDaysOfWeek(Locale.US);

[周日、周一、周二、周三、周四、周五、周六]

    sortAndPrintDaysOfWeek(Locale.forLanguageTag("ar-EG"));

[周六,周日,周一,周二,周三,周四,周五]

 类似资料:
  • 我正在尝试为我们的财务部门生成一些代码,他们需要一个字段,该字段将为他们提供一年中的当前一周,但以星期天为基础,这是一周的第一天。例如01-25-16(MM dd yyyy)将是第4周。然而,当我尝试使用和

  • 问题内容: 这些之间有什么区别: 有什么理由偏爱一个? 谢谢 问题答案: 为更正而更新: 在大多数情况下是相同的 ,从冬季切换到夏季时,请参见以下巴西示例: 截断发生在本地时间轴上。如果选择DAYS,则选择午夜。根据javadoc,-method最终会转换回新的方法,并将时间向前移动间隔的大小(1小时)。 在这种情况下,首先将zdt转换为(切断时间部分),然后在给定时区中查找其-part实际上是相

  • 我在本教程的帮助下制作了日历:http://droidwalk.blogspot.it/2012/11/android-calendar-sample.html ..但是这个日历从星期天开始,我想从星期一开始。。我试图改变价值观​​在函数中设置对象GregorianCalendar,但它不会给出所需的结果。本周从周一开始,但在某些月份,我们失去了第一周。我发现了一个类似的问题:从周一开始制作日历,

  • 我需要有一个对象,它与另一个对象完全相同,但具有不同的一周第一天(即:周日而不是周六)。 具体来说,我需要一个周日开始的阿拉伯埃及地区。我使用的日历控件只支持更改其区域设置,因此我需要它。

  • 也许我想多了。我想每周一上午9点发送本地通知,直到满足某些条件。我知道这可以通过设置的和组件来完成。我遇到的问题是我将传递给的值取决于正在使用的。如果我理解正确,则取决于用户的设置。例如,如果用户的日历周从周日开始,我会传递1到,但如果一周从周六开始,我会传递2。 我的问题是,我该如何解释时区、夏令时和周开始日之类的事情?

  • 我需要在我的dim_date中添加新的业务wee,实际上我有一个月中的星期,如下表所示,每7天计算一次。 但是对于这个商业周专栏,一周应该从星期一开始,到星期日结束,即使第一周只有一天(当一个月从星期日开始时),但如果月份从星期五开始,我应该将其视为该月的第一周。 你有什么建议来计算这个吗?谢谢