0

So i am trying to make 2 drop down menus in java gui that will allow the user to choose between time zones and compare two of them. But i am running into issues with trying to get the variable for the timezone the user chooses out of a lambda expression. I am still fairly new to java so any help would be appreciated please

Here is the code that is give me issues

 tz tz1= new tz();

ComboBox<String> cboNation = new ComboBox<>();
ObservableList<String> items = FXCollections.observableArrayList
  ("GMT+14", "GMT+13", "GMT+12", "GMT+11","GMT+10", "GMT+9", "GMT+8", 
   "GMT+7", "GMT+6", "GMT+5", "GMT+4", "GMT+3", "GMT+2", "GMT+1",
   "GMT0" ,"GMT-1", "GMT-2", "GMT-3", "GMT-4", "GMT-5", "GMT-6",
   "GMT-7", "GMT-8", "GMT-9", "GMT-10", "GMT-11", "GMT-12", "GMT-13", "GMT-14");
cboNation.getItems().addAll(items);
cboNation.setValue(items.get(0));
cboNation.setOnAction(e -> 
{

currentIndex = items.indexOf(cboNation.getValue());
TimeZone tz = TimeZone.getTimeZone(timezones[currentIndex]);
String Timezone2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(tz);
tz1.firstdisplay = Timezone2;
});

gridPane.add(new Label(tz1.firstdisplay), 0, 0);

I would like to be able to get tz out of the expression and be able to format it into a string that shows the date. It would come out on a gui if that helps at all.

edit I attempted the pass by reference the program now runs but the timezones do not show up in the gui. i add the line that is supposed to show them but nothing is happening

  • 1
    Welcome to Stack Overflow! Please [take the tour](http://stackoverflow.com/tour) to see how the site works and what questions are on topic here. See also: [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) – Joe C Apr 19 '17 at 21:47
  • Call a method from the lambda body with the selected time zone as param and then do stuff with it (u can assign it to a global variable which represents current timezone or whatever floats your boat) – Sneh Apr 19 '17 at 21:54
  • By the way, `TimeZone` has been supplanted by the java.time classes `ZoneId` and `ZoneOffset`. Also, your list refers to [*`offset-from-UTC`*](https://en.m.wikipedia.org/wiki/UTC_offset) values rather than time zones. A time zone is a history of changes to the offset for a particular region. Proper name for a time zone is continent/region such as `America/Montreal` or `Asia/Kolkata`. – Basil Bourque Apr 20 '17 at 09:10

2 Answers2

1

tl;dr

Defining ComboBox < ZoneOffset > offsetsMenu rather than <String>:

offsetsMenu.setOnAction( ( ActionEvent actionEvent ) -> { this.chosenOffset = offsetsMenu.getValue(); } );
  • I did not actually solve your problem, but simplified your code to eliminate the problem.
  • You are working too hard.
    • Use smart objects rather than dumb strings to back your menu, via generics.
    • Make your pop-up menu widget of type ZoneOffset to avoid look-ups into the backing list.
  • Use modern java.time classes only for date-time work. Here, specifically use Instant, ZoneOffset, ZoneId, and ZoneRules.
    • Never use TimeZone, SimpleDateFormat, java.util.Date, and so on.

Time zone versus offset

Offset

choose between time zones and compare two of them.

("GMT+14", "GMT+13", "GMT+12", "GMT+11","GMT+10", "GMT+9", "GMT+8", "GMT+7", "GMT+6", "GMT+5", "GMT+4", "GMT+3", "GMT+2", "GMT+1", "GMT0" ,"GMT-1", "GMT-2", "GMT-3", "GMT-4", "GMT-5", "GMT-6", "GMT-7", "GMT-8", "GMT-9", "GMT-10", "GMT-11", "GMT-12", "GMT-13", "GMT-14");

Those are not time zones. Those are offsets, a number of hours-minutes-seconds ahead or behind the prime meridian.

And they are not complete. An offset can be any number of hours-minutes-seconds. People in various places use various offsets. For example, modern India uses an offset of +05:30, five and a half hours ahead of UTC.

Time zone

A time zone is much more. A time zone is a history of past, present, and future changes to the offset used by the people of a particular region.

Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

java.time

You are using terrible old classes that are now supplanted by the modern java.time classes defined in JSR 310.

If you want to represent an offset of 14 hours ahead of UTC, use ZoneOffset.

ZoneOffset offset = ZoneOffset.ofHours( 14 ) ;

Represent an offset of five and a half hours ahead of UTC.

ZoneOffset offset = ZoneOffset.ofHoursMinutes( 5 , 30 ) ;

Even better, use time zones. The class for that is java.time.ZoneId, replacing the legacy TimeZone.

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;

Ask the ZoneId object for the offset currently in use, via the ZoneRules class.

ZoneOffset offsetInUseNowInIndia = z.getRules().getOffset( Instant.now() ) ;

choose between time zones and compare two of them

It would make more sense to let the user choose time zones rather than zone offsets. But if you insist on offsets…

Make your list of type ZoneOffset rather than string.

List< ZoneOffset > offsets ;

Let's get all offsets in use at a particular moment.

Instant instant = Instant.now() ;  // Capture the current moment as seen in UTC.

Loop all the time zones. For each, get the rules, and interrogate for the offset. Store in a sorted set, a TreeSet, to eliminate duplicates (many zones may share a particular offset at any particular moment).

Set < ZoneOffset > offsets = new TreeSet <>(); // A sorted set of `ZoneOffset`, eliminates duplicates. 

Instant instant = Instant.now(); // Capture the current moment as seen in UTC.
for ( String zoneIdString : ZoneId.getAvailableZoneIds() )
{
    ZoneId zoneId = ZoneId.of( zoneIdString );
    ZoneOffset offset = zoneId.getRules().getOffset( instant );
    offsets.add( offset );
}

Dump to console.

System.out.println( "offsets = " + offsets );

offsets = [+14:00, +13:45, +13:00, +12:00, +11:00, +10:30, +10:00, +09:30, +09:00, +08:45, +08:00, +07:00, +06:30, +06:00, +05:45, +05:30, +05:00, +04:30, +04:00, +03:30, +03:00, +02:00, +01:00, Z, -01:00, -02:00, -03:00, -03:30, -04:00, -05:00, -06:00, -07:00, -08:00, -09:00, -09:30, -10:00, -11:00, -12:00]

Feed a copy of offsets to make the list you need. (I do not use JavaFX.)

You asked:

format it into a string that shows the date

Take the Instant object in our code, the current moment as seen in UTC, and apply the ZoneOffset to get a OffsetDateTime. Again, no time zones here, just offsets. I recommend you use time zones instead (ZoneId versus ZoneOffset, ZonedDateTime versus OffsetDateTime). But you asked for offsets, so here we go.

If you list is text instead of ZoneOffset objects, make a ZoneOffset object.

ZoneOffset offset = ZoneOffset.of( "+05:30" ) ;

Apply the offset to the Instant object, producing a OffsetDateTime.

OffsetDateTime odt = instant.atOffset( offset ) ;

Generate text in standard ISO 8601 format.

String output = odt.toString() ;

odt.toString() = 2020-02-13T02:16:57.883278+05:30

That is close to your desired format. You can replace the T in the middle. And you omit the offset from your text. I do not recommend that, as it creates ambiguity for the person reading such a value. But if you insist, use the predefined constant DateTimeFormatter object that omits the offset, then replace the T.

String output = 
    odt
    .format( DateTimeFormatter.ISO_LOCAL_DATE_TIME )
    .replace( "T" , " " )
;

output = 2020-02-13 02:16:57.883278

Use data types in your JavaFX code

While I am new to JavaFX, it seems that your pop-up menu widget supports generics, and can represent smart objects rather than dumb strings. When making your ComboBox of type ZoneOffset (ComboBox< ZoneOffset >), the widget seems to be calling ZoneOffset.toString() by default for text to use displayed on screen to the user. That toString method generates text in standard ISO 8601 format.

Now we no longer need to do a look-up into the list of offsets. The user's choice is itself a ZoneOffset object! No need to look further.

Example app

I made my very first JavaFX app today, to demo this code.

I do not know how to add a Label to the Scene, so I will leave that as an exercise for the reader. But you can see here how we get a list of all offsets currently in use at this moment. And we assign that list of ZoneOffset objects to our pop-up menu widget, the ComboBox< ZoneOffset >. When user selects an item, that item is itself the ZoneOffset object from the list. So we no longer really care about the list per se. This strategy is common in object-oriented user-interface frameworks.

When you run the app, watch the console every time you select an item from the list.

screenshot of demo app running with source code in the background

package work.basil.example;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Set;
import java.util.TreeSet;

/**
 * JavaFX App
 * Untested code example.
 * <p>
 * © 2020 Basil Bourque.
 * Use by terms of ISC License: https://www.isc.org/licenses/  (basically, do anything but sue me)
 */
public class App extends Application
{
    ZoneOffset chosenOffset;

    @Override
    public void start ( Stage stage )
    {
        var javaVersion = SystemInfo.javaVersion();
        var javafxVersion = SystemInfo.javafxVersion();

        Set < ZoneOffset > offsets = new TreeSet <>();  // A sorted set of `ZoneOffset`, eliminates duplicates.

        Instant instant = Instant.now(); // Capture the current moment as seen in UTC.
        for ( String zoneIdString : ZoneId.getAvailableZoneIds() )
        {
            ZoneId zoneId = ZoneId.of( zoneIdString );
            ZoneOffset offset = zoneId.getRules().getOffset( instant );
            offsets.add( offset );
        }

        System.out.println( "offsets = " + offsets );

        ComboBox < ZoneOffset > offsetsMenu = new ComboBox <>();
        ObservableList < ZoneOffset > items = FXCollections.observableArrayList( offsets );
        offsetsMenu.getItems().addAll( items );
        offsetsMenu.getSelectionModel().selectFirst(); // Might be more orthodox than: offsetsMenu.setValue( items.get( 0 ) );
        this.chosenOffset = offsetsMenu.getSelectionModel().getSelectedItem(); // Record the default we assign.
        offsetsMenu.setOnAction( ( ActionEvent actionEvent ) ->
        {
            this.chosenOffset = offsetsMenu.getValue();
            System.out.println( "DEBUG - User chose ZoneOffset: " + this.chosenOffset );
        } );

        var scene = new Scene( new StackPane( offsetsMenu ) , 640 , 480 );
        stage.setScene( scene );
        stage.show();
    }

    public static void main ( String[] args )
    {
        launch();
    }
}

Further info

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
0

Actually you TimeZone tz variable is created inside your lambda expression and your are trying to use is outside your lambda expression with the code line String Timezone2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(tz);. You should declare the TimeZone tz variable as an instance variable.

MigSena
  • 218
  • 2
  • 7