将SQLite中的DateTime解析为Date

时间:2015-08-05 20:46:18

标签: android sqlite parsing datetime achartengine

我在将从SQLite数据库表中检索到的dataTime输出解析为Date格式时遇到了一些问题。

对于背景:我正在尝试使用AChartEngine将此表中的得分和日期时间显示在图表中。

主要问题是我一直收到有关数据集和渲染器错误的错误。 of series / null。我很确定这是因为日期没有被添加到系列中,因为解析时出错。我需要帮助试图找出问题,因为从在线阅读和查看有关Sqlite使用的模式的帖子我有正确的但我得到这个错误:

java.text.ParseException: Unparseable date: "5 Aug 2015 18:48" (at offset 1)

但是我的调试显示我从查询中转换的字符串是:

08-05 21:14:20.628  13955-13955/com.example.jamesliasides.myapplication D/dateTime db string:﹕ 2015-08-05 17:48:23

我在我的代码中用来解析字符串的模式是:

String pattern = "yyyy-MM-dd HH:mm:ss";

非常感谢任何帮助!

我的DatabaseHelper类:

public class DatabaseHelper extends SQLiteOpenHelper {

//SCORES Columns
public static final String SCORE_COLUMN_ID = "_ID";
public static final String SCORE_COLUMN_USER_ID = "user_ID";
public static final String SCORE_COLUMN_ACTIVITY_ID = "activity_ID";
public static final String SCORE_COLUMN_SCORE = "score";
public static final String SCORE_COLUMN_TIMESTAMP = "created_at";

//SCORES create command
private static final String CREATE_TABLE_SCORES = "CREATE TABLE "
        + SCORES_TABLE_NAME + "(" + SCORE_COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + SCORE_COLUMN_ACTIVITY_ID
        + " INTEGER," + SCORE_COLUMN_USER_ID + " INTEGER," + SCORE_COLUMN_SCORE + " INTEGER,"
        + SCORE_COLUMN_TIMESTAMP + " DATETIME default current_timestamp" + ")";

public DatabaseHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
    this.context = context;
}

@Override
public void onCreate(SQLiteDatabase db) {
    db.execSQL(CREATE_TABLE_ACTIVITIES);
    db.execSQL(CREATE_TABLE_USERS);
    db.execSQL(CREATE_TABLE_SCORES);
    Activity a1 = new Activity(1, "deadlift", "Standard dealift exercise is...");//do not include ID as the table autoincrements ids for
    Activity a2 = new Activity(2, "squat", "Standard squat exercise is...");

    ContentValues r1 = new ContentValues();
    r1.put(ACTIVITIES_COLUMN_NAME, a1.getName());
    r1.put(ACTIVITIES_COLUMN_DESCRIPTION, a1.getDescription());
    r1.put(ACTIVITIES_COLUMN_ID, a1.getId());

    // insert row
    long activity_id1 = db.insert(ACTIVITIES_TABLE_NAME, null, r1);
    Log.d("Insert Act DeadLift:", String.valueOf(activity_id1));


    ContentValues r2 = new ContentValues();
    r2.put(ACTIVITIES_COLUMN_NAME, a2.getName());
    r2.put(ACTIVITIES_COLUMN_DESCRIPTION, a2.getDescription());
    r2.put(ACTIVITIES_COLUMN_ID, a2.getId());

    // insert row
    long activity_id2 = db.insert(ACTIVITIES_TABLE_NAME, null, r2);
    Log.d("Insert Act Squat:", String.valueOf(activity_id2));

    @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    // on upgrade drop older tables
    db.execSQL("DROP TABLE IF EXISTS " + SCORES_TABLE_NAME);
    db.execSQL("DROP TABLE IF EXISTS " + ACTIVITIES_TABLE_NAME);
    db.execSQL("DROP TABLE IF EXISTS " + USERS_TABLE_NAME);
    onCreate(db);
}

/**
 * Inserts a user into its relation,reuturns -1 if fail, or the row id if successful.
 *
 * @param user
 * @return
 */
public long insertUser(User user) {
    SQLiteDatabase db = this.getWritableDatabase();

    Log.v("EditText", user.getName());
    Log.v("EditText", user.getEmail());
    Log.v("EditText", user.getPassword());

    ContentValues values = new ContentValues();
    values.put(USERS_COLUMN_NAME, user.getName());
    values.put(USERS_COLUMN_EMAIL, user.getEmail());
    values.put(USERS_COLUMN_PASSWORD, user.getPassword());
    values.put(USERS_COLUMN_AGE, user.getAge());
    values.put(USERS_COLUMN_WEIGHT, user.getWeight());
    values.put(USERS_COLUMN_HEIGHT, user.getHeight());


    //insert row
    long user_id = db.insert(USERS_TABLE_NAME, null, values);

    return user_id;
}

 /**
 * Insert a score into the scores table. Note the user ID is not input as the autoincrement
 * feature of the table will automatically apply one to it.
 * @param score
 * @return
 */
public long insertScore(Scores score){
    SQLiteDatabase db = this.getWritableDatabase();

    ContentValues values = new ContentValues();
    // values.put(SCORE_COLUMN_ID, score.getId());
    values.put(SCORE_COLUMN_SCORE, score.getScore());
    //values.put(SCORE_COLUMN_TIMESTAMP, score.getTimestamp()); DONT WANT to insert anything into this as its automated!
    values.put(SCORE_COLUMN_ACTIVITY_ID, score.getActivityID());
    values.put(SCORE_COLUMN_USER_ID, score.getUserID());

    //insert row
    long score_id = db.insert(SCORES_TABLE_NAME, null, values);

    return score_id;
}


/**
 * return a single entity from table by specifying its unique email address
 *
 * @param email
 * @return user
 */
public User getUser(String email, String password) {
    SQLiteDatabase db = this.getReadableDatabase();

   // String selectQuery = "SELECT * FROM " + USERS_TABLE_NAME + " WHERE " + USERS_COLUMN_EMAIL_ID + " = " + "?" + " AND " + USERS_COLUMN_PASSWORD + " = " + "?" ;
   // Log.e(LOG, selectQuery);

    //Cursor c = db.rawQuery(selectQuery, new String[]{email, password});
    String whereClause = "email =? AND password =?";
    String[] whereArgs = new String[]{email, password};
    Cursor c = db.query(USERS_TABLE_NAME, null, whereClause, whereArgs, null, null, null);

    User u = new User();

    if (c != null) {
        Log.i("cursor count: ", Integer.toString(c.getCount()));

        if (c.moveToFirst()) {
            Log.i("password parameter: ", password);
            do {
                u.setName(c.getString(c.getColumnIndex(USERS_COLUMN_NAME)));
                u.setEmail(c.getString(c.getColumnIndex(USERS_COLUMN_EMAIL)));
                u.setPassword(c.getString(c.getColumnIndex(USERS_COLUMN_PASSWORD)));
                u.setAge(c.getInt(c.getColumnIndex(USERS_COLUMN_AGE)));
                u.setWeight(c.getInt(c.getColumnIndex(USERS_COLUMN_WEIGHT)));
                u.setHeight(c.getInt(c.getColumnIndex(USERS_COLUMN_HEIGHT)));
                u.setId(c.getLong(c.getColumnIndex(USERS_COLUMN_ID)));

                Log.d("user", u.toString());
            } while (c.moveToNext());

        }
        c.close();
    }
    return u;
}

public XYMultipleSeriesDataset getTableScores(long userID, long activityID) throws ParseException {
    SQLiteDatabase db = this.getReadableDatabase();//error

    //SQLite query to get all Scores where ID and activity correspond to input params.
    String selectQuery = "SELECT " + SCORE_COLUMN_SCORE + ", " + SCORE_COLUMN_TIMESTAMP + ", " + SCORE_COLUMN_ID + " FROM " + SCORES_TABLE_NAME +
            " WHERE " + SCORE_COLUMN_USER_ID + " = '" +  userID + "'" + " AND " + SCORE_COLUMN_ACTIVITY_ID
            + " = '" + activityID + "'";                //String.valueOf(userID)
    Log.e(LOG, selectQuery);

    Cursor c = db.rawQuery(selectQuery, null);

    //dataset to add series to.
    XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
    //TimeSeries series = new TimeSeries("Line1");
    TimeSeries series2 = new TimeSeries("activity score");
    Log.d("cursor count", String.valueOf(c.getCount()));
    //mCurrentSeries.clear();
    if (c.moveToFirst()) {
        do {
            double value;
            int valueColumn = c.getColumnIndex("score");
            value = c.getDouble(valueColumn);
     //       String time;
      //      int timeColumn = c.getColumnIndex("created_at");
     //       time = String.valueOf(c.getDouble(timeColumn));

            String pattern = "yyyy-MM-dd HH:mm:ss";

            String dateTime = c.getString(c.getColumnIndexOrThrow(SCORE_COLUMN_TIMESTAMP));
            Log.d("dateTime db string:", dateTime);
            DateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = null;
            try {
               date = iso8601Format.parse(dateTime);
            } catch (ParseException e) {
                Log.e(LOG_TAG, "Parsing ISO8601 datetime failed", e);
            }
            long when = date.getTime();
            int flags = 0;
            flags |= android.text.format.DateUtils.FORMAT_SHOW_TIME;
            flags |= android.text.format.DateUtils.FORMAT_SHOW_DATE;
            flags |= android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
            flags |= android.text.format.DateUtils.FORMAT_SHOW_YEAR;

            String finalDateTime = android.text.format.DateUtils.formatDateTime(context,
                    when + TimeZone.getDefault().getOffset(when), flags);

            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
            //make the date object again from the string value of the DateTime record in the DB.
            date = simpleDateFormat.parse(finalDateTime);

      //      series2.add(date, value);
            series2.add(date, value);
            Log.i("values of time/score:", value + " + " + date);
        } while (c.moveToNext());
    }
    c.close();

    // dataset.addSeries(series);
    dataset.addSeries(series2);

    return dataset;
}

public Cursor getUserScore(long userID, long activityID){

    String selectQuery = "SELECT * FROM " + SCORES_TABLE_NAME + " WHERE " + SCORE_COLUMN_USER_ID
            + " = " + userID + " AND " + SCORE_COLUMN_ACTIVITY_ID + " = " + activityID
            + " ORDER BY " + SCORE_COLUMN_TIMESTAMP + " ASC";

    Log.e(LOG, selectQuery);
    SQLiteDatabase db = this.getReadableDatabase();
    Cursor c = db.rawQuery(selectQuery, null);

    return c;
}

这是我的viewGraphFragment类,其中使用viewGraph()方法调用Database方法:

public class viewGraphFragment extends Fragment {
    private DatabaseHelper mDbHelper;
    private Spinner spinnerActivity;
    private LinearLayout chart_layout;
    private long userID;


    public static viewGraphFragment newInstance(int someInt) {
        viewGraphFragment myFragment = new viewGraphFragment();

        Bundle args = new Bundle();
        args.putInt("someInt", someInt);
        myFragment.setArguments(args);

        return myFragment;
    }

    //set up the onClick listeners for the viewGraph button. Find user ID (sharedPrefs) and activity ID (choice from the spinner). Use these in a DB query. Put results in the AchartEngine XYseries.  
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_view_graph, container, false);
        mDbHelper = new DatabaseHelper(getActivity());

        Button backbutton = (Button) view.findViewById(R.id.btnBackToHome);
        backbutton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent;
                intent = new Intent(getActivity(), HomeActivity.class);
                startActivity(intent);
            }
        });

        Button button = (Button) view.findViewById(R.id.btnViewGraph);
        button.setOnClickListener(new View.OnClickListener() {
            /**
             * method called on click of the viewGraph button.
             * This button will call a DB method take the choice in the spinner as the Activity and the
             * User ID to get all relevent Scores to display in a Graph.
             */
            @Override
            public void onClick(View v) {
                //choose which activity scores to use.
                //get them from the database.
                //find out how to store them in a graph and a table.
                //display it nicely.
                String activityType = spinnerActivity.getSelectedItem().toString();
                //turn activityType to Activity ID.
                //long activityID = mDbHelper.findActivityID(activityType);
                long activityID = getActivityId(activityType);

                //getDemoDataset should return a dataset to be used for the Graph.
                XYMultipleSeriesDataset dataset = null;
                try {
                    dataset = mDbHelper.getTableScores(userID, activityID);//error activity type should be activityID not name

                    //if dataset is null we need an exception to handle this!!
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                //is the query actually returning anything from the DB or is it not displaying it properly.

                // Now we create the renderer
                XYSeriesRenderer renderer = new XYSeriesRenderer();
                renderer.setLineWidth(2);
                renderer.setColor(Color.RED);

                // Include low and max value
                renderer.setDisplayBoundingPoints(true);
                // we add point markers
                renderer.setPointStyle(PointStyle.CIRCLE);
                renderer.setPointStrokeWidth(3);
                renderer.setDisplayChartValues(true);
                renderer.setFillPoints(true);

                XYMultipleSeriesRenderer mRenderer = new XYMultipleSeriesRenderer();
                mRenderer.setChartTitle("Activity Scores: " + activityType);
                mRenderer.setXTitle("Time Days/Hours");
                mRenderer.setYTitle("Score in KG");
                // We want to avoid black border
                mRenderer.setMarginsColor(Color.argb(0x00, 0xff, 0x00, 0x00)); // transparent margins
                // Disable Pan on two axis
                mRenderer.setPanEnabled(false, false);
                mRenderer.setYAxisMax(200);
                mRenderer.setYAxisMin(0);
                mRenderer.setShowGrid(true); // we show the grid

                mRenderer.addSeriesRenderer(renderer);

                chart_layout = (LinearLayout) getActivity().findViewById(R.id.chart_layout);

                //needs a context a dataset and a renderer.
                GraphicalView chartView = ChartFactory.getLineChartView(getActivity(), dataset, mRenderer);//match sets in renderer and series!
                chart_layout.addView(chartView);
            }
        });
        return view;
    }

    //set up the spinners once activity is created. 
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        SharedPreferences sharedpreferences = this.getActivity().getSharedPreferences(MainActivity.MyPREFERENCES, Context.MODE_PRIVATE);
        userID = sharedpreferences.getLong(MainActivity.UserId, 0);

        //set up spinner
        spinnerActivity = (Spinner) this.getActivity().findViewById(R.id.spinnerActivity);
        ArrayAdapter<CharSequence> staticAdapter = ArrayAdapter
                .createFromResource(getActivity(), R.array.activity_type_array,
                        android.R.layout.simple_spinner_item);

        staticAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinnerActivity.setAdapter(staticAdapter);
    }

    public static long getActivityId(String activity){
        long id;
        switch (activity) {
            case "deadlift":
                id = 1; 
                break;
            case "squat":
                id = 2;
                break;
            case "bench press":
                id = 3;
                break;
            case "shoulder press":
                id = 4;
                break;
            case "bicep curl":
                id = 5;
                break;
            case "skullcrusher":
                id = 6;
                break;
            case "chin up":
                id = 7;
                break;
            case "pull up":
                id = 8;
                break;
            default:
                id = -1;
                break;
        }
        return id;
    }
}

Heres很长一段时间我的完整Logcat:

08-05 21:14:20.628  13955-13955/com.example.jamesliasides.myapplication E/DatabaseHelper﹕ SELECT score, created_at, _ID FROM scores WHERE user_ID = '1' AND activity_ID = '1'
08-05 21:14:20.628  13955-13955/com.example.jamesliasides.myapplication D/cursor count﹕ 2
08-05 21:14:20.628  13955-13955/com.example.jamesliasides.myapplication D/dateTime db string:﹕ 2015-08-05 17:48:23
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ java.text.ParseException: Unparseable date: "5 Aug 2015 18:48" (at offset 1)
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at java.text.DateFormat.parse(DateFormat.java:571)
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at com.example.jamesliasides.myapplication.DatabaseHelper.getTableScores(DatabaseHelper.java:607)
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at com.example.jamesliasides.myapplication.viewGraphFragment$2.onClick(viewGraphFragment.java:80)
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at android.view.View.performClick(View.java:4785)
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at android.view.View$PerformClick.run(View.java:19858)
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at android.os.Handler.handleCallback(Handler.java:739)
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at android.os.Handler.dispatchMessage(Handler.java:95)
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at android.os.Looper.loop(Looper.java:155)
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at android.app.ActivityThread.main(ActivityThread.java:5696)
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at java.lang.reflect.Method.invoke(Native Method)
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at java.lang.reflect.Method.invoke(Method.java:372)
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
08-05 21:14:20.638  13955-13955/com.example.jamesliasides.myapplication W/System.err﹕ at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
08-05 21:14:20.648  13955-13955/com.example.jamesliasides.myapplication E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.jamesliasides.myapplication, PID: 13955
java.lang.IllegalArgumentException: Dataset and renderer should be not null and should have the same number of series
        at org.achartengine.ChartFactory.checkParameters(ChartFactory.java:660)
        at org.achartengine.ChartFactory.getLineChartView(ChartFactory.java:68)
        at com.example.jamesliasides.myapplication.viewGraphFragment$2.onClick(viewGraphFragment.java:118)
        at android.view.View.performClick(View.java:4785)
        at android.view.View$PerformClick.run(View.java:19858)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:155)
        at android.app.ActivityThread.main(ActivityThread.java:5696)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)

1 个答案:

答案 0 :(得分:0)

问题似乎在这里:

        String finalDateTime = android.text.format.DateUtils.formatDateTime(context,
                when + TimeZone.getDefault().getOffset(when), flags);

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        //make the date object again from the string value of the DateTime record in the DB.
        date = simpleDateFormat.parse(finalDateTime);

而不是try-catch中数据库的结果。

您正在使用ormat模式:

        String pattern = "yyyy-MM-dd HH:mm:ss";

但是你的finalDateTime字符串是根据这个标志从formatDateTime构建的:

        int flags = 0;
        flags |= android.text.format.DateUtils.FORMAT_SHOW_TIME;
        flags |= android.text.format.DateUtils.FORMAT_SHOW_DATE;
        flags |= android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
        flags |= android.text.format.DateUtils.FORMAT_SHOW_YEAR;

显然会产生字符串"5 Aug 2015 18:48"