2

Given we can determine the first day of the week by soft-coding with Locale:

DayOfWeek firstDayOfWeek = WeekFields.of( Locale.US ).getFirstDayOfWeek() ;  // Sunday-Saturday.

… and given that Java comes with a built-in enum defining days of the week, DayOfWeek:

DayOfWeek[] dows = DayOfWeek.values() ;  // Monday-Sunday

How can we create another array or a list of whose elements are the DayOfWeek enum objects rearranged in order defined by our specified locale?

The goal is to represent all seven days of the week in the order defined by cultural norms as represented by a particular Locale.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Would generating the result list satisfy your requirements, or do we need to assume that you've got the list with the ISO order and we need to use that? In the latter case, does your list always hold all seven days and always exactly once each? – Ole V.V. Oct 22 '22 at 00:12
  • Relying on an assumption about the original list would mean waiting for your program to break when the assumption breaks. If I have understood your situation correctly, I would resort to sorting into the desired order. Probably not quite as efficient, but it guarantees that whatever was in the list in what order ends up in the correct order. – Ole V.V. Oct 22 '22 at 00:30
  • Here are three ways demonstrated online: https://rextester.com/MUKZY76895. First one as the question is asked, assuming that the original list contains each day once in the order defined by ISO 8601 and validating this assumption. Second a simpler solution accepting any list of DayOfWeek objects and just sorting it according to the locale. Finally another simple solution that generates the list without starting out from any existing list. – Ole V.V. Oct 23 '22 at 04:22
  • Related: [Get weekdays in order by locale](https://stackoverflow.com/questions/52742452/get-weekdays-in-order-by-locale) – Ole V.V. Nov 02 '22 at 10:11

2 Answers2

1

tl;dr

Collections.rotate( 
    new ArrayList<> ( List.of( DayOfWeek.values() ) ) ,   // Actually, you would instantiate elsewhere and pass here.
    DayOfWeek.MONDAY.ordinal() - WeekFields.of( Locale.US ).getFirstDayOfWeek().ordinal()  
)

Details

Fortunately, you need not do the list-rotation work yourself. The Collections utility class offers a rotate method. Pass your list along with an offset.

To quote the Javadoc:

Rotates the elements in the specified list by the specified distance. After calling this method, the element at index i will be the element previously at index (i - distance) mod list.size(), for all values of i between 0 and list.size()-1, inclusive. (This method has no effect on the size of the list.)

For example, suppose list comprises [t, a, n, k, s]. After invoking Collections.rotate(list, 1) (or Collections.rotate(list, -4)), list will comprise [s, t, a, n, k].

final List< DayOfWeek > iso8601 = List.of( DayOfWeek.values() ) ;  // Monday-Sunday, defined in ISO 8601 standard.
List< DayOfWeek > localeOrder = new ArrayList<>( iso8601 ) ;       // Duplicate the list of DayOfWeek objects.
Locale locale = Locale.US ;
DayOfWeek localeFirstDayOfWeek = WeekFields.of( locale ).getFirstDayOfWeek() ;  // Sunday-Saturday.
int distance = DayOfWeek.MONDAY.ordinal() - localeFirstDayOfWeek.ordinal() ;
Collections.rotate( localeOrder , distance ) ;

Dump to console.

System.out.println( iso8601 ) ;
System.out.println( localeOrder ) ;
System.out.println( distance ) ;

See that code run at Ideone.com.

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

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

-6

Or more briefly:

List< DayOfWeek > localeOrder = new ArrayList< DayOfWeek > ( List.of( DayOfWeek.values() ) ) ;   
Collections.rotate( 
    localeOrder , 
    DayOfWeek.MONDAY.ordinal() - WeekFields.of( Locale.US ).getFirstDayOfWeek().ordinal()  
) ;

See this code run at Ideone.com.

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

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Since `DayOfWeek.MONDAY.ordinal()` is `0`, it can be discarded. – Alexander Ivanchenko Oct 21 '22 at 23:28
  • 1
    @AlexanderIvanchenko Valid point. But I like the way its inclusion makes clear that conceptually we are making an offset from that Monday to our desired day. I expect the compiler would optimize away the `MONDAY.ordinal()` call. – Basil Bourque Oct 21 '22 at 23:30
  • I would expect passing `Arrays.asList(DayOfWeek.values())` to `rotate()` to work. Haven't tried it. – Ole V.V. Oct 22 '22 at 10:43
  • @OleV.V. I am not clear on (a) if [`DayOfWeek.values`](https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/time/DayOfWeek.html#values()) returns a modifiable or unmodifiable array, and (b) if that array will always be modifiable in future versions. So I am more comfortable with making an explicit copy of the contents which [`Arrays.asList`](https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/util/Arrays.html#asList(T...)) decidedly does *not*. Thus my use of `new ArrayList`. – Basil Bourque Oct 22 '22 at 20:40
  • I see your valid point. The method was introduced long before frozen arrays. So even though returning an unmodifiable array would be advantageous, I bet they dare not introduce that later. One would at least need to make sure to put the code under unit test so one discovers if it happens. – Ole V.V. Oct 23 '22 at 04:01
0

Here's how it can be done using List.subList() and Stream.concat().

The core idea

The rotated list can be constructed from two parts:

  • From the first day of the week to Sunday (inclusive);
  • From Monday to the first day of the week (exclusive). In case when the first day of the week is Monday, the second part would be empty.

That's how implementation might look like:

DayOfWeek firstDayOfWeek = WeekFields.of(Locale.US).getFirstDayOfWeek();   // the first Day of Week
    
List<DayOfWeek> initial = new ArrayList<>(EnumSet.allOf(DayOfWeek.class)); // initial list of Days of Week ordered according to ISO-8601
        
List<DayOfWeek> rotated = Stream.concat(
    initial.subList(firstDayOfWeek.ordinal(), DayOfWeek.SUNDAY.ordinal() + 1).stream(), // from the firstDayOfWeek to Sunday inclusive
    initial.subList(DayOfWeek.MONDAY.ordinal(), firstDayOfWeek.ordinal()).stream()      // from Monday to the firstDayOfWeek exclusive
).toList();
        
rotated.forEach(System.out::println); // printing the result

Output:

SUNDAY
MONDAY
TUESDAY
WEDNESDAY
THURSDAY
FRIDAY
SATURDAY

A link to Online Demo

Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46