在if语句中解析日期并仅显示规定时间范围内的结果

Parsing Date in an if-statement and showing only results in stipulated time range

目前我正在编写一个 java 程序来找出 Hammer or other Candlestick pattern 在哪一天形成。

用户在执行程序时必须输入 2 个日期作为参数,例如java ReadingTest 2016-09-03 2016-10-31,程序会寻找2016-09-03到2016-10-31的Hammer形态

代码如下:

import java.io.*;
import java.util.*;
import java.text.*;

public class ReadingTest
{
    public static void main(String[] args) throws IOException,ParseException
    {
    //Import file to java
    File file = new file("table.csv");

    //Read the file
    Scanner infile = new Scanner(file);

    //Skip the first line in table.csv
    infile.nextLine();

    //Define format of date
    SImpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    //Name the variables user enters
    Date start = sdf.parse(args[0]);
    Date end = sdf.parse(args[1]);

    //Create ArrayList for each column of data
    ArrayList<String> date = new ArrayList<String>();
    ArrayList<Double> open = new ArrayList<Double>();
    ArrayList<Double> high = new ArrayList<Double>();
    ArrayList<Double> low = new ArrayList<Double>();
    ArrayList<Double> close = new ArrayList<Double>();

    while (infile.hasNext())
    {
        //Tokenize columns by comma
        String[] data = infile.nextLine().split(",");
        //Organize each column of data to one index of data array
        date.add(data[0]);
        open.add(Double.parseDouble(data[1]));
        high.add(Double.parseDouble(data[2]));
        low.add(Double.parseDouble(data[3]));
        close.add(Double.parseDouble(data[4]));
    }
    //Show options and ask user to choose
    System.out.println("1. Hammer");
    System.out.println("2. Three white soldiers");
    System.out.println("3. Bullish kicker");

    //Record user input and execute corresponding code
    Scanner input = new Scanner(System.in);
    int choice = input.nextInt();

    if (choice == 1)
        for (int i = 0; i < date.size(); i++)
            if (close.get(i) > open.get(i) &&
                close.get(i) > ((high.get(i)) + (low.get(i)))/2 &&
                ((close.get(i) - low.get(i))/2 > (high.get(i) - close.get(i)))
            System.out.println("Pattern found: " + date.get(i));
}
}

代码到这里为止都可以正常工作。但是,最后一行代码的输出是 dd/MM/yyyy 格式,我尝试使用 sdf.parse(date.get(i)) 而不是 date.get(i) 来以 yyyy-MM-dd 格式显示结果。 运行 代码有 sdf.parse(date.get(i)) returns 错误如下:

Exception in thread "main" java.text.ParseException: Unparseable date: 
"25/10/2016" at 
java.text.DateFormat.parse(Unknown source) at ReadingTest.main(ReadingTest.java:59)

我还尝试仅显示显示 Hammer 的日期,使用:

(date.get(i).after(start) && date.get(i).before(end))

并导致

error: cannot find symbol
symbol: method before(Date)
location: class String

CSV 文件如下所示:

Date       Open  High  Low  Close  
31/10/2016 58.25 58.65 58.2 58.35
28/10/2016 58.95 59    58.3 58.35
.
.
.
1/8/2016   50.8  51.1 50.75  50.8

应该如何修改代码以使其工作?

文件中的格式不是格式 "yyyy-MM-dd",而是格式 "dd/MM/yyyy",因此您无法使用变量 sdf 解析它。您可以定义第二个日期格式

SImpleDateFormat sdfParse = new SimpleDateFormat("dd/MM/yyyy");

然后用这个进行解析并用你的格式化:

sdf.format(sdfParse.parse(date.get(i)))

希望得到更好的结果。

我猜你想要的是这个

SimpleDateFormat hammerFormat = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat slashFormat = new SimpleDateFormat("dd/MM/yyyy");

这样您就可以将您的日期解析为 yyyy-MM-dd 表示形式,就像这样

hammerFormat.format(slashFormat.parse(date.get(i))));

完整代码

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Scanner;

public class ReadingTest {
    public static void main(String[] args) throws IOException, ParseException {
        // Import file to java
        File file = new File("table.csv");

        // Read the file
        Scanner infile = new Scanner(file);

        // Skip the first line in table.csv
        infile.nextLine();

        // Define format of date
        SimpleDateFormat hammerFormat = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat slashFormat = new SimpleDateFormat("dd/MM/yyyy");

        // Name the variables user enters
        Date start = hammerFormat.parse(args[0]);
        Date end = hammerFormat.parse(args[1]);

        // Create ArrayList for each column of data
        ArrayList < String > date = new ArrayList < String > ();
        ArrayList < Double > open = new ArrayList < Double > ();
        ArrayList < Double > high = new ArrayList < Double > ();
        ArrayList < Double > low = new ArrayList < Double > ();
        ArrayList < Double > close = new ArrayList < Double > ();

        while (infile.hasNext()) {
            // Tokenize columns by comma
            String[] data = infile.nextLine().split(",");
            // Organize each column of data to one index of data array
            date.add(data[0]);
            open.add(Double.parseDouble(data[1]));
            high.add(Double.parseDouble(data[2]));
            low.add(Double.parseDouble(data[3]));
            close.add(Double.parseDouble(data[4]));
        }
        // Show options and ask user to choose
        System.out.println("1. Hammer");
        System.out.println("2. Three white soldiers");
        System.out.println("3. Bullish kicker");

        // Record user input and execute corresponding code
        Scanner input = new Scanner(System.in);
        int choice = input.nextInt();

        if (choice == 1)
            for (int i = 0; i < date.size(); i++)
                if (close.get(i) > open.get(i) && close.get(i) > ((high.get(i)) + (low.get(i))) / 2 && ((close.get(i) - low.get(i)) / 2 > (high.get(i) - close.get(i))))
                    System.out.println("Pattern found: " + hammerFormat.format(slashFormat.parse(date.get(i))));
    }
}

编辑:

像这样的 .csv 文件格式(因为在代码中它说 .split(",")

31/10/2016, 58.25, 58.65, 58.20, 58.35
28/10/2016, 58.95, 59.00, 58.30, 58.35
01/08/2016, 50.80, 51.10, 50.75, 50.80

对我来说效果很好。我在执行程序的时候传了两个参数2016-09-03 2016-10-31

tl;博士

Parsing Date

日期时间工作仅使用 java.time classes。

LocalDate start = LocalDate.parse( "2018-10-27" );  // Parse input string as a date-only value (no time-of-day, no time zone), a `java.time.LocalDate` object.

… in an if-statement and showing only results in stipulated time range

if ( 
    ( ! stockDay.getDate().isBefore( start ) )     // A shorter way to ask "is equal to OR later" is "is NOT before". 
    && 
    stockDay.getDate().isBefore( stop )            // Half-Open approach, where beginning is *inclusive* while the ending is *exclusive*.
) { … }

更好的是,使用 ThreeTen-Extra 库中的 LocalDateRange class 表示您的开始-停止日期范围。

if ( 
     LocalDateRange.of( start , stop )
                   .contains( LocalDate.parse( "2018-10-27" ) )
) { … }

详情

How the code should be amended to make it work?

你可能会后悔问了这个问题。我对这个答案有点发疯,对 Candlestick Hammer, and wanting to work more with Java Streams.

感到好奇

修复日期时间处理

您使用的是麻烦的旧日期时间 classes,它在几年前就被取代了,但是 java.time classes.

此外,您正在滥用那些遗留的 classes。您将一个仅限日期的值放入日期和时间类型中。请改用 java.time.LocalDate 来获取仅限日期的值。

您未能定义格式模式来匹配您的输入。您的模式显示 "yyyy-MM-dd" 但您的输入是按日-月-年顺序而不是年-月-日顺序。定义格式模式以匹配您的字符串输入。使用现代 class、DateTimeFormatter

DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu" ) ;

解析您的输入字符串。

LocalDate ld = LocalDate.parse( "31/10/2016" , f ) ;

ld.toString(): 2018-10-31

明确日期时间对象没有“格式”。格式与表示日期时间 value/object 的文本相关,与从日期时间对象生成的 String 对象相关。但是日期时间对象和 String 保持独立和不同。

顺便说一下,不要为您的输入使用这种自定义或本地化的格式。 将日期时间值作为文本交换时,始终使用标准 ISO 8601 格式。当 parsing/generating 字符串时,java.time classes 默认使用这些标准格式。

为数据模型

定义一个class

与其弄乱数组或一堆 List 对象,不如为您的数据定义一个 class。将其命名为类似 StockDay 的名称,以表示股票在特定日期的表现。

切勿使用 doubleDouble,也不要使用 floatFloat 来表示金钱。这些类型使用 floating-point technology that trades away accuracy to get faster execution performance. Instead use the BigDecimal class;速度较慢,但​​准确。

在此 class 上,我们将业务逻辑包含在定义 Candlestick Hammer 中。为简单起见,我采用了更严格的定义,不允许上部“阴影”。所有这些代码仅用于演示,完全未经测试:使用风险自负。

package com.basilbourque.example;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Objects;

public class StockDay implements Comparable < StockDay > {

    // Example data:
    // Date       Open  High  Low  Close
    // 31/10/2016 58.25 58.65 58.2 58.35

    // ---------|  Members  |------------------------
    private LocalDate date;
    private BigDecimal open, high, low, close;
    private Boolean isHammer;

    // ---------|  Constructors  |------------------------
    public StockDay ( final LocalDate localDateArg , final BigDecimal openArg , final BigDecimal highArg , final BigDecimal lowArg , final BigDecimal closeArg ) {
        // In real work, add defensive code to validate data such as no nulls, only positive numbers, reasonable dates.
        this.date = localDateArg;
        this.open = openArg;
        this.high = highArg;
        this.low = lowArg;
        // Verify the high is greater than or equal to the low.
        if ( this.high.compareTo( this.low ) < 0 ) {
            throw new IllegalArgumentException( "The passed High is below the passed Low for Date of " + this.date + ". Not possible." );
        }
        this.close = closeArg;
        this.isHammer = this.determineHammer();
    }

    private Boolean determineHammer () {
        // A hammer is a price pattern in candlestick charting that occurs when a security trades significantly lower than its opening, but rallies later in the day to close either above or near its opening price. This pattern forms a hammer-shaped candlestick, in which the body is at least half the size of the tail or wick.
        // Read more: Hammer https://www.investopedia.com/terms/h/hammer.asp#ixzz5G6rqtbkv
        // See also: http://www.onlinetradingconcepts.com/TechnicalAnalysis/Candlesticks/Hammer.html

        // Caveat: This code is a quick rough draft, not thought-through, and totally untested. Use at your own risk. For demonstration purposes only.

        // First check if the High is above the Close. A Hammer has little or no upper  "shadow" (line protruding above the box). We'll go with "no shadow" for simplicity here.
        if ( this.high.compareTo( this.close ) > 0 ) { // if high > close, not a hammer.
            return Boolean.FALSE;
        }

        // Proceed with next check: Is "tail" (lower shadow) at least twice as long as height of box.
        BigDecimal closeOpenDeltaAbsolute_BoxHeight = this.close.subtract( this.open ).abs();
        BigDecimal lowerOfCloseOrOpen = ( this.close.compareTo( this.open ) < 0 ) ? this.close : this.open;  // If x is smaller than y, use x. If x is greater than or equal to y, use y.
        BigDecimal lowerShadowHeight = lowerOfCloseOrOpen.subtract( this.low );
        // A Hammer has a long lower shadow (delta between either Close or Open, whichever is lower, and the Low), at least twice as tall as the box (Close-Open absolute delta).
        BigDecimal requiredMinimumLengthFactorOfShadow = new BigDecimal( "2" );
        BigDecimal doubleCloseOpenDeltaAbsolute = closeOpenDeltaAbsolute_BoxHeight.multiply( requiredMinimumLengthFactorOfShadow );
        Boolean hammer = ( lowerShadowHeight.compareTo( doubleCloseOpenDeltaAbsolute ) > 0 );
        return hammer;

    }


    // ---------|  Accessors  |------------------------
    // All fields are read-only. Just getters, no setters.
    public LocalDate getDate () {
        return this.date;
    }

    public BigDecimal getOpen () {
        return this.open;
    }

    public BigDecimal getHigh () {
        return this.high;
    }

    public BigDecimal getLow () {
        return this.low;
    }

    public BigDecimal getClose () {
        return this.close;
    }

    public Boolean isHammer () {
        return this.isHammer;
    }

    // ---------|  Override `Object`  |------------------------
    @Override
    public String toString () {
        return "StockDay{ " +
                "date=" + this.date +
                ", open=" + this.open +
                ", high=" + this.high +
                ", low=" + this.low +
                ", close=" + this.close +
                ", isHammer=" + this.isHammer +
                " }";
    }

    @Override
    public boolean equals ( final Object oArg ) {
        if ( this == oArg ) return true;
        if ( oArg == null || getClass() != oArg.getClass() ) return false;
        final StockDay stockDay = ( StockDay ) oArg;
        return Objects.equals( this.date , stockDay.date ) &&
                Objects.equals( this.open , stockDay.open ) &&
                Objects.equals( this.high , stockDay.high ) &&
                Objects.equals( this.low , stockDay.low ) &&
                Objects.equals( this.close , stockDay.close );
        // Perhaps this should be coded to only consider the `LocalDate` field alone.
    }

    @Override
    public int hashCode () {
        return Objects.hash( this.date , this.open , this.high , this.low , this.close );
        // Perhaps this should be coded to only consider the `LocalDate` field alone.
    }


    @Override
    public int compareTo ( final StockDay o ) {
        // Compare the date field only.
        int result = this.getDate().compareTo( o.getDate() );
        return result;
    }
}

定义一个class用于加载数据

创建 class 以加载您的 CSV 数据。

package com.basilbourque.example;

import java.io.Reader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

public class StockDayLoader {
    final private DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );  // Tip: Instead of this custom format, use standard ISO 8601 formats when exchanging date-time values as text.

    public List < StockDay > loadFrom ( final Reader input ) {
        final List < StockDay > stockDays = new ArrayList <>();  // To be populated by lines of data read from the input.

        try (  // try-with-resources
               Scanner scanner = new Scanner( input ).useDelimiter( "\r\n" ) ; // Delimiter is a comma between fields.
        ) {
            scanner.useLocale( Locale.US ); // Determines cultural norms such as FULL STOP versus COMMA for decimal point in a `BigDecimal`.

            // Skip first line, the column headers.
            if ( scanner.hasNextLine() ) {
                String headers = scanner.nextLine(); // Ignore returned String.
                if ( ! "Date,Open,High,Low,Close".equals( headers ) ) { // Verify expected input.
                    throw new IllegalArgumentException( "The passed Readable object’s first row does not consist of expected column header names." );
                }
            }

            while ( scanner.hasNextLine() ) {
                String line = scanner.nextLine(); // Grab entire line.
                try (
                        Scanner lineScanner = new Scanner( line ).useDelimiter( "," ).useLocale( Locale.US ) ;
                ) {
                    String dateInput = lineScanner.next();
                    LocalDate date = LocalDate.parse( dateInput , this.dateFormatter );
                    try {
                        BigDecimal open = lineScanner.nextBigDecimal();
                        BigDecimal high = lineScanner.nextBigDecimal();
                        BigDecimal low = lineScanner.nextBigDecimal();
                        BigDecimal close = lineScanner.nextBigDecimal();
                        StockDay stockDay = new StockDay( date , open , high , low , close );
                        stockDays.add( stockDay );  // Collect the newly intanstiated `StockDay` object.
                    } catch ( InputMismatchException e ) {
                        System.out.println( "ERROR The next token does not match the Decimal regular expression, or is out of range.  " );
                        e.printStackTrace();
                    }
                }
            }

            return stockDays;
        }
    }


    // -----------|  Testing/Demo  |------------------------

    public static String bogusData () {
        final String eol = "\r\n";   // RFC 4180 requires CrLf as end-of-line.
        final StringBuilder sb = new StringBuilder();
        sb.append( "Date,Open,High,Low,Close" + eol );
        sb.append( "31/10/2016,58.25,58.65,58.2,58.35" + eol );
        sb.append( "28/10/2016,58.95,59,58.3,58.35" + eol );
        sb.append( "27/10/2016,58.78,58.22,33.3,58.55" + eol ); // Hammer.
        sb.append( "26/10/2016,58.95,59.05,58.43,58.45" + eol );
        sb.append( "25/10/2016,58.99,58.44,22.2,58.57" + eol ); // Hammer.
        String s = sb.toString();
        return s;
    }

    public static void main ( String[] args ) {
        String s = StockDayLoader.bogusData();
        Reader reader = new StringReader( s );

        StockDayLoader loader = new StockDayLoader();
        List < StockDay > list = loader.loadFrom( reader );

        System.out.println( list );
    }

}

Apache Commons CSV

更好的是,与其编写自己的 CSV reader,不如利用在 Apache Commons CSV.

等库中找到的现有的经过良好测试的代码
package com.basilbourque.example;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

public class StockDayLoaderEasy {

    final private DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );  // Tip: Instead of this custom format, use standard ISO 8601 formats when exchanging date-time values as text.

    public List < StockDay > loadFrom ( final Reader reader ) {
        final List < StockDay > stockDays = new ArrayList <>();  // To be populated by lines of data read from the input.

        Iterable < CSVRecord > records = null;
        try {
            records = CSVFormat.RFC4180.parse( reader );
        } catch ( IOException eArg ) {
            eArg.printStackTrace();
        }

        // Read each column. Names:  "Date,Open,High,Low,Close"
        for ( CSVRecord record : records ) {
            LocalDate date = LocalDate.parse( record.get( "Date" ) , this.dateFormatter );
            BigDecimal open = new BigDecimal( record.get( "Open" ) );
            BigDecimal high = new BigDecimal( record.get( "High" ) );
            BigDecimal low = new BigDecimal( record.get( "Low" ) );
            BigDecimal close = new BigDecimal( record.get( "Close" ) );

            StockDay stockDay = new StockDay( date , open , high , low , close );
            stockDays.add( stockDay );  // Collect the newly intanstiated `StockDay` object.
        }
        return stockDays;
    }

    // -----------|  Testing/Demo  |------------------------

    public static String bogusData () {
        final String eol = "\r\n";   // RFC 4180 requires CrLf as end-of-line.
        final StringBuilder sb = new StringBuilder();
        sb.append( "Date,Open,High,Low,Close" + eol );
        sb.append( "31/10/2016,58.25,58.65,58.2,58.35" + eol );
        sb.append( "28/10/2016,58.95,59,58.3,58.35" + eol );
        sb.append( "27/10/2016,58.78,58.22,33.3,58.55" + eol ); // Hammer.
        sb.append( "26/10/2016,58.95,59.05,58.43,58.45" + eol );
        sb.append( "25/10/2016,58.99,58.44,22.2,58.57" + eol ); // Hammer.
        String s = sb.toString();
        return s;
    }

    public static void main ( String[] args ) {
        String s = StockDayLoader.bogusData();
        Reader reader = new StringReader( s );

        StockDayLoader loader = new StockDayLoader();
        List < StockDay > list = loader.loadFrom( reader );

        System.out.println( list );
    }
}

齐心协力

创建一个应用程序来练习这些曲子。

该问题的目标是找出哪些股票日报告符合 (a) 日期范围内的日期,并且 (b) 是锤子。

这里展示了几个简短的例子。有些使用老式的 Java 语法,有些使用现代的 Streams/Lambda 语法,两种方式的结果相同。阅读代码注释以获取指导。

package com.basilbourque.example;

import org.threeten.extra.LocalDateRange;

import java.io.Reader;
import java.io.StringReader;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class HammerTime {
    public static void main ( String[] args ) {
        HammerTime hammerTime = new HammerTime();
        hammerTime.doIt();
    }

    private void doIt () {
        // Load all data.
        Reader reader = new StringReader( StockDayLoader.bogusData() );
        List < StockDay > stockDays = new StockDayLoader().loadFrom( reader );
        Collections.sort( stockDays );  // Sort chronologically, ascending order, oldest first. For newest first, call `Collections.reverse`.
        System.out.println( "All stockDays = " + stockDays );

        // Find hammers using the old-fashioned way.
        List < StockDay > hammers = new ArrayList <>();
        for ( StockDay stockDay : stockDays ) {
            if ( stockDay.isHammer() ) {
                hammers.add( stockDay );
            }
        }
        System.out.println( "hammers: " + hammers );

        // Find hammers using modern Streams/Lambda features, while tolerating NULLs.
        List < StockDay > hammers2 = stockDays.stream()
                .filter( stockDay -> Objects.equals( stockDay.isHammer() , Boolean.TRUE ) )  // Use `Objects.equals` to tolerate NULL values.
                .collect( Collectors.toList() );
        System.out.println( "hammers2: " + hammers2 );

        // Find hammers using modern Streams/Lambda features, assuming no NULL values exist.
        List < StockDay > hammers3 = stockDays.stream()
                .filter( stockDay -> stockDay.isHammer().equals( Boolean.TRUE ) )  // Simpler syntax than above, if you are certain of no NULLs.
                .collect( Collectors.toList() );
        System.out.println( "hammers3: " + hammers3 );

        // Find hammers within a certain date-range, per the original Question.

        // Parse the user’s input start/stop dates.
        LocalDate start = LocalDate.parse( "2016-10-26" ); // This range should pick up the hammer on the 27th while omitting the hammer on the 25th.
        LocalDate stop = LocalDate.parse( "2016-10-28" ); // Usual practice in defining a span-of-time is the Half-Open approach, where the beginning is *inclusive* while the ending is *exclusive*.

        // Find hammers within date range using the old-fashioned syntax, with built-in classes.
        List < StockDay > hammersInDateRange1 = new ArrayList <>();
        for ( StockDay stockDay : stockDays ) {
            if ( stockDay.isHammer() ) {
                if ( ( ! stockDay.getDate().isBefore( start ) ) && stockDay.getDate().isBefore( stop ) ) {
                    hammersInDateRange1.add( stockDay );
                }
            }
        }
        System.out.println( "hammersInDateRange1: " + hammersInDateRange1 );

        // Find hammers within date range using the old-fashioned syntax, with the ThreeTen-Extra library and its `LocalDateRange` class.  http://www.threeten.org/threeten-extra/
        final LocalDateRange dateRange = LocalDateRange.of( start , stop );
        List < StockDay > hammersInDateRange2 = new ArrayList <>();
        for ( StockDay stockDay : stockDays ) {
            if ( stockDay.isHammer() ) {
                if ( dateRange.contains( stockDay.getDate() ) ) {
                    hammersInDateRange2.add( stockDay );
                }
            }
        }
        System.out.println( "hammersInDateRange2: " + hammersInDateRange2 );

        // Find hammers within date range using modern Streams/Lambda syntax, with the ThreeTen-Extra library and its `LocalDateRange` class.  http://www.threeten.org/threeten-extra/
        List < StockDay > hammersInDateRange3 = stockDays.stream()
                .filter( stockDay -> stockDay.isHammer() && dateRange.contains( stockDay.getDate() ) )  // Assumes no NULLs.
                .collect( Collectors.toList() );
        System.out.println( "hammersInDateRange3: " + hammersInDateRange3 );


    }
}

当运行.

All stockDays = [StockDay{ date=2016-10-25, open=58.99, high=58.44, low=22.2, close=58.57, isHammer=true }, StockDay{ date=2016-10-26, open=58.95, high=59.05, low=58.43, close=58.45, isHammer=false }, StockDay{ date=2016-10-27, open=58.78, high=58.22, low=33.3, close=58.55, isHammer=true }, StockDay{ date=2016-10-28, open=58.95, high=59, low=58.3, close=58.35, isHammer=false }, StockDay{ date=2016-10-31, open=58.25, high=58.65, low=58.2, close=58.35, isHammer=false }]

hammers: [StockDay{ date=2016-10-25, open=58.99, high=58.44, low=22.2, close=58.57, isHammer=true }, StockDay{ date=2016-10-27, open=58.78, high=58.22, low=33.3, close=58.55, isHammer=true }]

hammers2: [StockDay{ date=2016-10-25, open=58.99, high=58.44, low=22.2, close=58.57, isHammer=true }, StockDay{ date=2016-10-27, open=58.78, high=58.22, low=33.3, close=58.55, isHammer=true }]

hammers3: [StockDay{ date=2016-10-25, open=58.99, high=58.44, low=22.2, close=58.57, isHammer=true }, StockDay{ date=2016-10-27, open=58.78, high=58.22, low=33.3, close=58.55, isHammer=true }]

hammersInDateRange1: [StockDay{ date=2016-10-27, open=58.78, high=58.22, low=33.3, close=58.55, isHammer=true }]

hammersInDateRange2: [StockDay{ date=2016-10-27, open=58.78, high=58.22, low=33.3, close=58.55, isHammer=true }]

hammersInDateRange3: [StockDay{ date=2016-10-27, open=58.78, high=58.22, low=33.3, close=58.55, isHammer=true }]


关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

您可以直接与数据库交换 java.time 对象。使用 JDBC driver compliant with JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* classes.

从哪里获得java.time classes?

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.